Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1244554
  • 博文数量: 261
  • 博客积分: 4196
  • 博客等级: 上校
  • 技术积分: 3410
  • 用 户 组: 普通用户
  • 注册时间: 2012-02-17 17:05
文章分类

全部博文(261)

文章存档

2018年(1)

2017年(22)

2016年(2)

2015年(8)

2014年(27)

2013年(40)

2012年(161)

分类: LINUX

2017-11-15 09:22:23

原文:http://blog.csdn.net/tennysonsky/article/details/44062173

  如何让两个套接字都能成功绑定8000端口呢?这时候就需要要到端口复用了。端口复用允许在一个应用程序可以把 n 个套接字绑在一个端口上而不出错。
设置socket的SO_REUSEADDR选项,即可实现端口复用:

int opt = 1;  
// sockfd为需要端口复用的套接字  setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const void *)&opt, sizeof(opt)); 
 

SO_REUSEADDR可以用在以下四种情况下。 (摘自《Unix网络编程》卷一,即UNPv1)

1、当有一个有相同本地地址和端口的socket1处于TIME_WAIT状态时,而你启动的程序的socket2要占用该地址和端口,你的程序就要用到该选项。

2、SO_REUSEADDR允许同一port上启动同一服务器的多个实例(多个进程)。但每个实例绑定的IP地址是不能相同的。在有多块网卡或用IP Alias技术的机器可以测试这种情况。

3、SO_REUSEADDR允许单个进程绑定相同的端口到多个socket上,但每个socket绑定的ip地址不同。这和2很相似,区别请看UNPv1。

4、SO_REUSEADDR允许完全相同的地址和端口的重复绑定。但这只用于UDP的多播,不用于TCP。

需要注意的是,设置端口复用函数要在绑定之前调用,而且只要绑定到同一个端口的所有套接字都得设置复用
代码如下

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <unistd.h>
  5. #include <sys/socket.h>
  6. #include <netinet/in.h>
  7. #include <arpa/inet.h>

  8. int main(int argc, char *argv[])
  9. {
  10.     int sockfd_one;
  11.     int err_log;
  12.     sockfd_one = socket(AF_INET, SOCK_DGRAM, 0); //创建UDP套接字one
  13.     if(sockfd_one < 0)
  14.     {
  15.     perror("sockfd_one");
  16.     exit(-1);
  17.     }

  18.     // 设置本地网络信息
  19.     struct sockaddr_in my_addr;
  20.     bzero(&my_addr, sizeof(my_addr));
  21.     my_addr.sin_family = AF_INET;
  22.     my_addr.sin_port = htons(8000);        // 端口为8000
  23.     my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
  24.     
  25.     // 在sockfd_one绑定bind之前,设置其端口复用
  26.     int opt = 1;
  27.     setsockopt( sockfd_one, SOL_SOCKET,SO_REUSEADDR,
  28.                     (const void *)&opt, sizeof(opt) );

  29.     // 绑定,端口为8000
  30.     err_log = bind(sockfd_one, (struct sockaddr*)&my_addr, sizeof(my_addr));
  31.     if(err_log != 0)
  32.     {
  33.         perror("bind sockfd_one");
  34.         close(sockfd_one);        
  35.         exit(-1);
  36.     }

  37.     int sockfd_two;
  38.     sockfd_two = socket(AF_INET, SOCK_DGRAM, 0); //创建UDP套接字two
  39.     if(sockfd_two < 0)
  40.     {
  41.         perror("sockfd_two");
  42.         exit(-1);
  43.     }

  44.     // 在sockfd_two绑定bind之前,设置其端口复用
  45.     opt = 1;
  46.     setsockopt( sockfd_two, SOL_SOCKET,SO_REUSEADDR,
  47.                     (const void *)&opt, sizeof(opt) );
  48.     
  49.     // 新套接字sockfd_two,继续绑定8000端口,成功
  50.     err_log = bind(sockfd_two, (struct sockaddr*)&my_addr, sizeof(my_addr));
  51.     if(err_log != 0)
  52.     {
  53.         perror("bind sockfd_two");
  54.         close(sockfd_two);        
  55.         exit(-1);
  56.     }

  57.     close(sockfd_one);
  58.     close(sockfd_two);

  59.     return 0;
  60. }

阅读(2847) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~