2010-07-30 181 views
2

从我从this thread得到的答案根据,我已经创造了这个:Socket编程的C,使用select()函数

//Server 

    sock_init(); //from SFL, see http://legacy.imatix.com/html/sfl/ 

    timeout = 50000; 

    serv_sock_input[0] = TCP(1234); 
    serv_sock_input[1] = UDP(9876); 

    input_protocols[0] = "tcp"; 
    input_protocols[1] = "udp"; 

    while (1) 
    { 
     FD_ZERO(&sock_set); 
     for (x = 0; x<number_of_inputs; x++) 
     { 
      FD_SET(serv_sock_input[x], &sock_set); 
     } 

     select_timeout.tv_sec = timeout; 
     select_timeout.tv_usec = 0; 

     if (select(0, &sock_set, NULL, NULL, &select_timeout) == 0) 
      printf("No requests"); 
     else 
     { 
      for (x = 0; x<number_of_inputs; x++) 
      { 
       if (FD_ISSET(serv_sock_input[x],&sock_set)) 
       { 
        printf("\nRequest on port %d: \n", x); 
        if ((strcmp(input_protocols[x],"tcp")) == 0) //in this case, 0 returned == TRUE 
        { 
         accept_socket(serv_sock_input[x]); 
         printf("Input TCP Port %d\n",x); 
         close_socket(serv_sock_input[x]); 
        } 
        else 
        { 
         printf("Input UDP Port %d\n",x); 
        } 
       } 
      } 
     } 
    } 
    sock_term(); 
} 

int TCP (unsigned short port) 
{ 
    int sock;       
    struct sockaddr_in servAddr; 

    if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) 
     exit(1); 

    memset(&servAddr, 0, sizeof(servAddr)); 
    servAddr.sin_family = AF_INET;   
    servAddr.sin_addr.s_addr = htonl(INADDR_ANY); 
    servAddr.sin_port = htons(port);    

    if (bind(sock, (struct sockaddr *) &servAddr, sizeof(servAddr)) < 0) 
     exit(1); 

    if (listen(sock, 5) < 0) 
     exit(1); 

    return sock; 
} 

int UDP (unsigned short port) 
{ 
    int sock;      /* socket to create */ 
    struct sockaddr_in servAddr; /* Local address */ 

    /* Create socket for sending/receiving datagrams */ 
    if ((sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) 
     exit(1); 

    /* Construct local address structure */ 
    memset(&servAddr, 0, sizeof(servAddr)); /* Zero out structure */ 
    servAddr.sin_family = AF_INET;    /* Internet address family */ 
    servAddr.sin_addr.s_addr = htonl(INADDR_ANY); /* Any incoming interface */ 
    servAddr.sin_port = htons(port);  /* Local port */ 

    /* Bind to the local address */ 
    if (bind(sock, (struct sockaddr *) &servAddr, sizeof(servAddr)) < 0) 
     exit(1); 


    return sock; 
} 

//Client 
sock_init(); 

    if ((client_sock_output = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) 
     exit(1); 

    memset(&client_addr, 0, sizeof(client_addr)); 
    client_addr.sin_family  = AF_INET; 
    client_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); 
    client_addr.sin_port  = htons(1234); 

    if (connect(client_sock_output, (struct sockaddr *) &client_addr, sizeof(client_addr)) < 0) 
     exit(1); 

    closesocket(client_sock_output); 

    sock_term(); 

Wh在服务器启动时,服务器在if(select(...))声明处被阻止。

所以当我运行服务器,然后运行客户端时,客户端连接到服务器(有时在连接之前运行客户端需要几次)。然后if(select...))陈述不再是真实的,它进行到else。

之后,客户端关闭连接和程序。但是,这是我的问题发生的地方,if(select(...))声明总是错误的。我得到这个输出:

Request on port 0: 
Input TCP Port 0 

Request on port 1: 
Input UDP Port 1 

这个输出永远重复。它怎么不卡在if(select(...))

回答

5

您有两个问题:您不明白accept()如何在TCP中工作,并且您需要读取UDP中的传入数据。

select()告诉你一个监听套接字有连接来接受,或者读取套接字有数据要读。

要选择停止告诉你这一点,你需要实际读取数据或接受连接。

在你的UDP分支中,你需要调用receiv来实际获取数据。如果你不这样做,选择将不断告诉你,你有数据。

在你的TCP分支中,你调用accept_socket。我不知道你的实现是什么,但关闭刚才调用accept()的套接字很可能是错误的。 accept()为你返回一个新的套接字 - 你应该用于IO的套接字。如果需要关闭任何东西,那就是新的套接字。

1

请检查您为什么在服务器中安装此软件。

如果(选择(0, & sock_set,NULL,NULL,& select_timeout)== 0)

如果(选择(maxDescPlus1 & sock_set替换它, NULL,NULL,& select_timeout)== 0)

其中maxDescPlus1 - >是sel的描述符的数量ect加1值。