Linux下的socket编程实践(三)端口复用和 P2P多进程服务器

Socket端口复用

先说为什么要使用socket端口复用?如果你遇到过这样的问题:server程序重启之后,无法连接,需要过一段时间才能连接上?

 1.一个监听(listen)server已经启动
  2.当有client有连接请求的时候,server产生一个子进程去处理该client的事物.
3.server主进程终止了,但是子进程还在占用该连接处理client的事情.虽然子进程终止了,但是由于子进程没有终止,该socket的引用计数不会为0,所以该socket不会被关闭.
4.server程序重启。

这个时候由于端口已经被占用,所以无法重新再bind,这也使得TIME_WAIT状态设计的原因之一。

[cpp]  view plain copy
  1. int getsockopt(int sockfd, int level, int optname,    
  2.                void *optval, socklen_t *optlen);    
  3. int setsockopt(int sockfd, int level, int optname,    
  4.                const void *optval, socklen_t optlen);    
SO_REUSEADDR允许同一个端口上绑定多个IP,只要这些IP不同。服务端尽可能使用SO_REUSEADDR,在绑定之前尽可能调用setsockopt来设置SO_REUSEADDR套接字选项。该选项可以使得server不必等待TIME_WAIT状态消失。

[cpp]  view plain copy
  1. int setsockopt(  
  2.     SOCKET s,  
  3.     int level,  
  4.     int optname,  
  5.     const char* optval,  
  6.     int optlen  
  7. );  
s(套接字): 指向一个打开的套接口描述字
level:(级别): 指定选项代码的类型。
SOL_SOCKET: 基本套接口
IPPROTO_IP: IPv4套接口
IPPROTO_IPV6: IPv6套接口
IPPROTO_TCP: TCP套接口
optname(选项名): 选项名称
optval(选项值): 是一个指向变量的指针 类型:整形,套接口结构, 其他结构类型:linger{}, timeval{ }
optlen(选项长度) :optval 的大小
在bind之前添加源码,支持端口复用:

[cpp]  view plain copy
  1. int on = 1;    
  2. if (setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,    
  3.                &on,sizeof(on)) == -1)    
  4.     err_exit("setsockopt SO_REUSEADDR error");    
   另外,我想到一个问题:因为SO_REUSEADDR是为了应对重启server使用的,那么未使用选项的服务端在accept之后产生一个新的socket连接,那么这个连接真的会分配一个新的端口吗?当我实践之后却发现这些新的socket连接和bind的端口是一致的!!难道一个端口可以绑定多个套接字吗,当然不是,下面是分析:

   首先,一个端口肯定只能绑定一个socket。我认为,服务器端的端口在bind的时候已经绑定到了监听套接字socetfd所描述的对象上,accept函数新创建的socket对象其实并没有进行端口的占有,而是复制了socetfd的本地IP和端口号,并且记录了连接过来的客户端的IP和端口号。

   那么,当客户端发送数据过来的时候,究竟是与哪一个socket对象通信呢?

   客户端发送过来的数据可以分为2种,一种是连接请求,一种是已经建立好连接后的数据传输。

   由于TCP/IP协议栈是维护着一个接收和发送缓冲区的。在接收到来自客户端的数据包后,服务器端的TCP/IP协议栈应该会做如下处理:如果收到的是请求连接的数据包,则传给监听着连接请求端口的socetfd套接字,进行accept处理;如果是已经建立过连接后的客户端数据包,则将数据放入接收缓冲区。这样,当服务器端需要读取指定客户端的数据时,则可以利用socketfd_new 套接字通过recv或者read函数到缓冲区里面去取指定的数据(因为socketfd_new代表的socket对象记录了客户端IP和端口,因此可以鉴别)。

   在解决这个问题的时候,参考了博客  http://ticktick.blog.51cto.com/823160/779866


处理多客户连接:

[cpp]  view plain copy
  1. void echo(int clientfd);    
  2. int main()    
  3. {    
  4.     int listenfd = socket(AF_INET, SOCK_STREAM, 0);    
  5.     if (listenfd == -1)    
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值