MultiSocket 监听 Linux 套接字编程

Posted

技术标签:

【中文标题】MultiSocket 监听 Linux 套接字编程【英文标题】:MultiSocket Listening Linux Socket Programing 【发布时间】:2014-02-10 22:58:49 【问题描述】:

这是我编写的简单代码。服务器响应端口 2923、2924 和 2925 上的 CONNECTIONS。

当我运行程序时,服务器只接受来自 2923 端口的连接。有人可以帮帮我吗?谢谢

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/time.h>

void handle_client(int cliend_fd)


  int ret = accept(cliend_fd, NULL, 0);
  if (ret < 0)
  
    printf("Accept Error\n");
  

  else
  
    printf("Client Accepted\n");
    shutdown(ret, 2);
  


int main()

  int count = 3;
  int PORT = 2923;

  struct sockaddr_in address;
  int MasterSocket[count];
  int i = 0;
  fd_set readfds;

  int maxfd;
  maxfd = -1;
  int SelectSession;

  struct timespec TimeOut;
  TimeOut.tv_sec = 2;
  TimeOut.tv_nsec = 2;

  for (i = 0; i < count; i++)
  
    MasterSocket[i] = socket(AF_INET, SOCK_STREAM, 0);
  

  for (i = 0; i < count; i++)
  
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = inet_addr("127.0.0.1");
    address.sin_port = PORT + i;
    if (bind(MasterSocket[i], (struct sockaddr *) &address, sizeof(address))
        < 0)
    
      perror("Bind\n");
      getchar();
    

    printf("SockerDesriptor %d---bind %d\n", MasterSocket[i], PORT + i);
  

  for (i = 0; i < count; i++)
  
    if (listen(MasterSocket[i], 4) < 0)
    
      perror("Listen");
      getchar();
      //return 1;
    
    else
    
      printf("Listening on Port %d---\n", PORT + i);
    
  

  while (1)
  
    FD_ZERO(&readfds);
    int status;

    for (i = 0; i < count; i++)
    
      FD_SET(MasterSocket[i], &readfds);
      if (MasterSocket[i] > maxfd)
      
        maxfd = MasterSocket[i];
      
      printf("%d Added to FD_SET Descriptor %d \n\n", PORT + i,
          MasterSocket[i]);
    

    //status = 0;
    printf("############Waiting for Connection\n");
    status = pselect(maxfd + 1, &readfds, NULL, NULL, &TimeOut, NULL );
    if (status < 0)
    
      perror("Status");
      getchar();
      return 1;
    

    else if (status == 0)
    
      printf("TimeOut occured\n");
    

    else
    
      //printf("Status %d\n", status);
      SelectSession = -1;
      for (i = 0; i < count; i++)
      
        //printf("Checking Set %d\n", i);
        if (FD_ISSET(MasterSocket[i], &readfds))
        
          //printf("Matching Set %d\n", i);
          SelectSession = MasterSocket[i];
          printf("SelectSession %d\n", MasterSocket[i]);
          if (SelectSession == -1)
          
            //shutdown (MasterSocket[i], 2);
            //continue;
            break;
          
          else
          
            printf("In Handle\n");
            handle_client(SelectSession);
            getchar();
          

        
        else
        
          printf("Not in FD_ISSET\n");

        
      
    

    /*for (i=0; i<count; i++)
     
     shutdown (MasterSocket[i], 2);
     
     */
  

  return 0;

【问题讨论】:

在程序执行过程中,bind()listen()pselect() 和/或accept() 是否有任何错误? 代码编译时没有警告吗? 这里的代码在完成#define _POSIX_C_SOURCE 200112L 后编译干净,以提取pselect() 的原型并按预期工作。 你用什么连接服务器? 使用了客户端程序。连接端口。仅接受 2923 【参考方案1】:

从 while 循环中删除 getchar()

pselect 服务器等待获取字符之后,因此不再允许连接客户端。

或者你必须在每个客户端连接后在服务器中输入一个字符

并使用htons将端口号更改为网络字节顺序

程序:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/time.h>

void handle_client (int cliend_fd)

    int ret = accept(cliend_fd, NULL, 0);
    if ( ret < 0 )
        printf("Accept Error\n");
    else 
        printf ("Client Accepted\n");
        shutdown (ret, 2);
    
    return;


int main()

    int count = 3, PORT = 8000, opt = 1, i = 0;
    int MasterSocket[count];
    int maxfd = -1, SelectSession;
    fd_set readfds;
    struct sockaddr_in address;

    struct timespec TimeOut;
    TimeOut.tv_sec = 2;
        TimeOut.tv_nsec = 2;

    for(i=0; i<count; i++)
    
        MasterSocket[i] = socket(AF_INET , SOCK_STREAM , 0);
        printf("socket created : %d\n", MasterSocket[i]);
    

    for(i=0; i<count; i++)
    
        address.sin_family = AF_INET;
        address.sin_addr.s_addr = inet_addr("192.168.1.4");
        address.sin_port = htons(PORT+i);
        if( setsockopt(MasterSocket[i], SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt)) < 0 )     
            perror("setsockopt1");
            return -1;
        
        if (bind(MasterSocket[i], (struct sockaddr *)&address, sizeof(address)) < 0) 
            perror ("Bind\n");
            return -1;
        
        printf("SockerDesriptor %d---bind %d\n", MasterSocket[i], PORT+i);
    

    for(i=0; i<count;i++)
    
        if (listen(MasterSocket[i], 4) < 0) 
                perror ("Listen\n");
                return -1;
        
        else
            printf("Listening on Port %d---\n", PORT+i);    
    

    while(1)
       
        FD_ZERO(&readfds);
        int status;
        for (i = 0; i < count; i++)
        
            FD_SET(MasterSocket[i], &readfds);
            if (MasterSocket[i] > maxfd)
                maxfd = MasterSocket[i];
        

        status = pselect(maxfd + 1, &readfds, NULL, NULL, &TimeOut, NULL );
        if(status < 0)
            perror("Status");
        /* else if(status == 0)
            printf("TimeOut occured\n"); */
        else if(status > 0) 
            for (i = 0; i < count; i++)
            
                if (FD_ISSET(MasterSocket[i], &readfds)) 
                    SelectSession = MasterSocket[i];
                    printf("SelectSession %d\n", MasterSocket[i]);
                    handle_client(SelectSession);
                    //getchar();
                
            
        
    
    return 0;
       

【讨论】:

工作中...感谢您的帮助 \m/。是的,我查了SO_REUSEADDRgetchar()。我忽略了一个小细节。我用count +1 调用了“pselect”而不是maxfd+1【参考方案2】:

这一行

 address.sin_port = PORT + i;

应该是

 address.sin_port = htons(PORT + i);

确保端口按网络字节顺序存储。


另外你应该close()一个套接字描述符在关闭它之后,如果你不再需要它,释放与之相关的系统资源。

【讨论】:

以上是关于MultiSocket 监听 Linux 套接字编程的主要内容,如果未能解决你的问题,请参考以下文章

linux内核如何区分连接套接字和监听套接字?

linux系统实现多个进程监听同一个端口

在不相关的进程之间共享套接字(监听)

如何使用Win7设置QTcpServer单独监听端口

Linux之ss命令

Linux中ss用法详解