首页 > 其他 > 详细

Socket 相关的知识

时间:2014-04-09 20:03:55      阅读:595      评论:0      收藏:0      [点我收藏+]

1、关于PF_INET和AF_INET的区别  

在写网络程序的时候,建立TCP socket:
 sock = socket(PF_INET, SOCK_STREAM, 0);
然后在绑定本地地址或连接远程地址时需要初始化sockaddr_in结构,其中指定address family时一般设置为AF_INET,即使用IP。

相关头文件中的定义:AF = Address Family
                            PF = Protocol Family
                            AF_INET = PF_INET

在windows中的Winsock2.h中,

                           #define AF_INET 0
                           #define PF_INET AF_INET

所以在windows中AF_INET与PF_INET完全一样.  

    而在Unix/Linux系统中,在不同的版本中这两者有微小差别.对于BSD,是AF,对于POSIX是PF.

    理论上建立socket时是指定协议,应该用PF_xxxx,设置地址时应该用AF_xxxx。当然AF_INET和PF_INET的值是相同的,混用也不会有太大的问题。也就是说你socket时候用PF_xxxx,设置的时候用AF_xxxx也是没关系的,这点随便找个TCPIP例子就可以验证出来了。如下,不论是AF_INET还是PF_INET都是可行的,只不过这样子的话,有点不符合规范。

bubuko.com,布布扣
 /* 服务器端开始建立socket描述符 */
// if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1) 
 if((sockfd=socket(PF_INET,SOCK_STREAM,0))==-1) 
 {
     fprintf(stderr,"Socket error:%s\n\a",strerror(errno));
     exit(1);
 }

 /* 服务器端填充 sockaddr结构 */ 
 bzero(&server_addr,sizeof(struct sockaddr_in));
 server_addr.sin_family=AF_INET;
 //server_addr.sin_family=PF_INET;
 server_addr.sin_addr.s_addr=htonl(INADDR_ANY);
 server_addr.sin_port=htons(portnumber);
bubuko.com,布布扣
在函数socketpair与socket的domain参数中有AF_UNIX,AF_LOCAL,AF_INET,PF_UNIX,PF_LOCAL,PF_INET.
这几个参数有AF_UNIX=AF_LOCAL, PF_UNIX=PF_LOCAL, AF_LOCAL=PF_LOCAL, AF_INET=PF_INET.
但是对于socketpair与socket的domain参数,使用PF_LOCAL系列,
而在初始化套接口地址结构时,则使用AF_LOCAL.
例如:
     z = socket(PF_LOCAL, SOCK_STREAM, 0);
     adr_unix.sin_family = AF_LOCAL;
Linux 下的address family定义
bubuko.com,布布扣
/* Supported address families. */
#define AF_UNSPEC    0
#define AF_UNIX        1    /* Unix domain sockets         */
#define AF_LOCAL    1    /* POSIX name for AF_UNIX    */
#define AF_INET        2    /* Internet IP Protocol     */
#define AF_AX25        3    /* Amateur Radio AX.25         */
#define AF_IPX        4    /* Novell IPX             */
#define AF_APPLETALK    5    /* AppleTalk DDP         */
#define AF_NETROM    6    /* Amateur Radio NET/ROM     */
#define AF_BRIDGE    7    /* Multiprotocol bridge     */
#define AF_ATMPVC    8    /* ATM PVCs            */
#define AF_X25        9    /* Reserved for X.25 project     */
#define AF_INET6    10    /* IP version 6            */
#define AF_ROSE        11    /* Amateur Radio X.25 PLP    */
#define AF_DECnet    12    /* Reserved for DECnet project    */
#define AF_NETBEUI    13    /* Reserved for 802.2LLC project*/
#define AF_SECURITY    14    /* Security callback pseudo AF */
#define AF_KEY        15      /* PF_KEY key management API */
#define AF_NETLINK    16
#define AF_ROUTE    AF_NETLINK /* Alias to emulate 4.4BSD */
#define AF_PACKET    17    /* Packet family        */
#define AF_ASH        18    /* Ash                */
#define AF_ECONET    19    /* Acorn Econet            */
#define AF_ATMSVC    20    /* ATM SVCs            */
#define AF_RDS        21    /* RDS sockets             */
#define AF_SNA        22    /* Linux SNA Project (nutters!) */
#define AF_IRDA        23    /* IRDA sockets            */
#define AF_PPPOX    24    /* PPPoX sockets        */
#define AF_WANPIPE    25    /* Wanpipe API Sockets */
#define AF_LLC        26    /* Linux LLC            */
#define AF_CAN        29    /* Controller Area Network      */
#define AF_TIPC        30    /* TIPC sockets            */
#define AF_BLUETOOTH    31    /* Bluetooth sockets         */
#define AF_IUCV        32    /* IUCV sockets            */
#define AF_RXRPC    33    /* RxRPC sockets         */
#define AF_ISDN        34    /* mISDN sockets         */
#define AF_PHONET    35    /* Phonet sockets        */
#define AF_IEEE802154    36    /* IEEE802154 sockets        */
#define AF_CAIF        37    /* CAIF sockets            */
#define AF_MAX        38    /* For now.. */

/* Protocol families, same as address families. */
#define PF_UNSPEC    AF_UNSPEC
#define PF_UNIX        AF_UNIX
#define PF_LOCAL    AF_LOCAL
#define PF_INET        AF_INET
#define PF_AX25        AF_AX25
#define PF_IPX        AF_IPX
#define PF_APPLETALK    AF_APPLETALK
#define PF_NETROM    AF_NETROM
#define PF_BRIDGE    AF_BRIDGE
#define PF_ATMPVC    AF_ATMPVC
#define PF_X25        AF_X25
#define PF_INET6            AF_INET6
#define PF_ROSE        AF_ROSE
#define PF_DECnet    AF_DECnet
#define PF_NETBEUI    AF_NETBEUI
#define PF_SECURITY    AF_SECURITY
#define PF_KEY        AF_KEY
#define PF_NETLINK    AF_NETLINK
#define PF_ROUTE    AF_ROUTE
#define PF_PACKET    AF_PACKET
#define PF_ASH        AF_ASH
#define PF_ECONET    AF_ECONET
#define PF_ATMSVC    AF_ATMSVC
#define PF_RDS        AF_RDS
#define PF_SNA        AF_SNA
#define PF_IRDA        AF_IRDA
#define PF_PPPOX            AF_PPPOX
#define PF_WANPIPE    AF_WANPIPE
#define PF_LLC        AF_LLC
#define PF_CAN        AF_CAN
#define PF_TIPC        AF_TIPC
#define PF_BLUETOOTH    AF_BLUETOOTH
#define PF_IUCV        AF_IUCV
#define PF_RXRPC    AF_RXRPC
#define PF_ISDN        AF_ISDN
#define PF_PHONET    AF_PHONET
#define PF_IEEE802154    AF_IEEE802154
#define PF_CAIF        AF_CAIF
#define PF_MAX        AF_MAX
bubuko.com,布布扣

2、linux之shutdown()与close()函数

1.close()函数

int close(int sockfd);     //返回成功为0,出错为-1.

close 一个套接字的默认行为是把套接字标记为已关闭,然后立即返回到调用进程,该套接字描述符不能再由调用进程使用,也就是说它不能再作为readwrite的第一个参数,然而TCP将尝试发送已排队等待发送到对端的任何数据,发送完毕后发生的是正常的TCP连接终止序列。

    在多进程并发服务器中,父子进程共享着套接字,套接字描述符引用计数记录着共享着的进程个数,当父进程或某一子进程close掉套接字时,描述符引用计数会相应的减一,当引用计数仍大于零时,这个close调用就不会引发TCP的四路握手断连过程。

2.shutdown()函数

int shutdown(int sockfd,int howto);  //返回成功为0,出错为-1.

该函数的行为依赖于howto的值

    1.SHUT_RD:值为0,关闭连接的读这一半。

    2.SHUT_WR:值为1,关闭连接的写这一半。

    3.SHUT_RDWR:值为2,连接的读和写都关闭。

    终止网络连接的通用方法是调用close函数。但使用shutdown能更好的控制断连过程(使用第二个参数)。

3.两函数的区别

    closeshutdown的区别主要表现在:

    close函数会关闭套接字ID,如果有其他的进程共享着这个套接字,那么它仍然是打开的,这个连接仍然可以用来读和写,并且有时候这是非常重要的,特别是对于多进程并发服务器来说。

   shutdown会切断进程共享的套接字的所有连接,不管这个套接字的引用计数是否为零,那些试图读得进程将会接收到EOF标识,那些试图写的进程将会检测到SIGPIPE信号,同时可利用shutdown的第二个参数选择断连的方式。

    下面将展示一个客户端例子片段来说明使用closeshutdown所带来的不同结果:

     客户端有两个进程,父进程和子进程,子进程是在父进程和服务器建连之后fork出来的,子进程发送标准输入终端键盘输入数据到服务器端,知道接收到EOF标识,父进程则接受来自服务器端的响应数据。

bubuko.com,布布扣
   s=connect(...); 

   if( fork() ){    
       while( gets(buffer) >0) 
           write(s,buf,strlen(buffer)); 
close(s); exit(
0); } else { while( (n=read(s,buffer,sizeof(buffer)){ do_something(n,buffer);
wait(
0); exit(0); }
bubuko.com,布布扣

对于这段代码,我们所期望的是子进程获取完标准终端的数据,写入套接字后close套接字,并退出,服务器端接收完数据检测到EOF(表示数据已发送完),也关闭连接,并退出。接着父进程读取完服务器端响应的数据,并退出。然而,事实会是这样子的嘛,其实不然!子进程close套接字后,套接字对于父进程来说仍然是可读和可写的,尽管父进程永远都不会写入数据。因此,此socket的断连过程没有发生,因此,服务器端就不会检测到EOF标识,会一直等待从客户端来的数据。而此时父进程也不会检测到服务器端发来的EOF标识。这样服务器端和客户端陷入了死锁(deadlock)。如果用shutdown代替close,则会避免死锁的发生。

bubuko.com,布布扣
if( fork() ) {   
      while( gets(buffer) 
         write(s,buffer,strlen(buffer)); 

      shutdown(s,1);  
      exit(0); 
 } 
bubuko.com,布布扣

 

 

Socket 相关的知识,布布扣,bubuko.com

Socket 相关的知识

原文:http://www.cnblogs.com/cslunatic/p/3653828.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!