2012-09-02 67 views
1

我正在檢出一個由計算器成員編寫的程序atanos關於2010年將多個客戶端連接到單個服務器時,我稍微修改了他的程序以接受來自命令的連接詳細信息行,下面是服務器和cient代碼。即使連接被接受,「recv」也不起作用

Server.c

int main(int argc, char **argv) 
{ 
    fd_set fds, readfds; 
    int i, clientaddrlen, portno; 
    int clientsock[2], rc, numsocks = 0, maxsocks = 2; 

    if (argc < 2){ 
     fprintf(stderr,"ERROR, no port provided\n"); 
     exit(1); 
    } 

    int serversock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 

    if (serversock == -1) perror("Socket"); 

    portno = atoi(argv[1]); 
    struct sockaddr_in serveraddr, clientaddr; 
    bzero(&serveraddr, sizeof(struct sockaddr_in)); 
    serveraddr.sin_family = AF_INET; 
    serveraddr.sin_addr.s_addr = htonl(INADDR_ANY); 
    serveraddr.sin_port = htons(portno); 

    if (-1 == bind(serversock, (struct sockaddr *)&serveraddr,sizeof(struct sockaddr_in))) perror("Bind"); 

    if (-1 == listen(serversock, SOMAXCONN)) perror("Listen"); 

    FD_ZERO(&fds); 
    FD_SET(serversock, &fds); 

    while(1) { 
    readfds = fds; 
    rc = select(FD_SETSIZE, &readfds, NULL, NULL, NULL); 

    if (rc == -1){ 
     perror("Select"); 
     break; 
    } 

    for (i = 0; i < FD_SETSIZE; i++) 
    { 
     if (FD_ISSET(i, &readfds)){ 
     if (i == serversock){ 
      if (numsocks < maxsocks){ 
      clientsock[numsocks] = accept(serversock,(struct sockaddr *) &clientaddr, 
       (socklen_t *)&clientaddrlen); 

      if (clientsock[numsocks] == -1) perror("Accept"); 
      else printf("Connection accepted\n"); 

      FD_SET(clientsock[numsocks], &fds); 
      numsocks++; 
      } 
      else 
      printf("Ran out of socket space.\n"); 
     } 
     else 
     { 
      int messageLength = 10; 
      char message[messageLength+1]; 
      int numOfChRead, index = 0, limit = messageLength+1; 

      numOfChRead = recv(clientsock[i], message, messageLength,0); 

      if(numOfChRead > 0) 
       printf("Data Received !!! length: %d Message: %s", numOfChRead, message); 
      else 
       printf("Nothing read\n"); 
     } 
     } 
    } 
    } 
    close(serversock); 
    return 0; 
} 

Client.c

int main(int argc, char **argv) 
{ 
    struct sockaddr_in servaddr; 
    struct hostent *server; 
    int portno, bytesSent = 0; 

    if (argc < 3){ 
     fprintf(stderr,"Usage %s hostname port\n", argv[0]); 
     exit(0); 
    } 

    portno = atoi(argv[2]); 
    int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 
    if (sock == -1) perror("Socket"); 

    server = gethostbyname(argv[1]); 

    if (server == NULL){ 
     fprintf(stderr,"ERROR, no such host\n"); 
     exit(0); 
    } 

    bzero((void *) &servaddr, sizeof(servaddr)); 
    servaddr.sin_family = AF_INET; 

    servaddr.sin_port = htons(portno); 
    bcopy((char *)server->h_addr,(char *)&servaddr.sin_addr.s_addr,server->h_length); 

    if (-1 == connect(sock, (struct sockaddr *)&servaddr, sizeof(servaddr))) perror("Connect"); 

    while(1) { 
    char message[10]; 
    fgets(message, 10, stdin); 
    message[10] = '\0'; 

    bytesSent = send(sock, message, strlen(message), 0); 

    if(bytesSent == -1) printf("Sending failed with errno %d", errno); 
    else printf("Sent %d characters", bytesSent); 
    } 
    close(sock); 
} 

我可以看到,服務器接受多個連接,但是當我從任何客戶端的發送的消息,則服務器中的recv API不會讀取任何內容。客戶端的發送API成功,我可以看到所有的字符都被髮送了。有人可以評論嗎?

回答

2

問題是你從來沒有真正把客戶端連接在讀fd_set

行:

readfds = fds; 

復位readfds到它只有在它的服務器(監聽)套接字的狀態。在每次調用select之前,您需要完全重新設置fd_set中的每個客戶端文件描述符。

可能是其他問題(這是很多代碼需要通過),但這似乎是最可能的問題。

(順便說一句,我不知道該轉讓是合法的。我不認爲這是在執行任何要求有fd_set簡單,可複製的結構。)

+0

或者,他可以改變'FD_SET(clientsock [numsocks] &fds);'來'FD_SET(clientsock [numsocks],&readfds);'此外,POSIX要求是FD_SET必須是一個結構,我已經不看到一個不可複製的* nix。 – nos

+0

POSIX強加一個結構體,它並不強制該結構體不包含指針,如果是,則通過'='的結構體複製將不會執行OP需要的結構。這就是說,我不知道這個副本不會工作的實現,有些環境提供了一個'FD_COPY' - 對於那些使用它而不是一個普通的任務可能更安全的地方 – Mat

+0

非常感謝很多人,它幫助了很多 – Neo

1

有在你的代碼是多個錯誤。您沒有正確使用選擇呼叫。 select的第一個參數需要您正在監聽的最高數量的fds加1.第二個參數包含要監視的fds列表。

我用fdmax取代了你的FD_SETSIZE。我更正了代碼中的問題並粘貼在下面。

8 int main(int argc, char **argv) 
    9 { 
10 fd_set fds, readfds; 
11 int i, clientaddrlen, portno; 
12 int clientsock[2], rc, numsocks = 0, maxsocks = 2; 
13 int fdmax=0; 
14 
15 if (argc < 2){ 
16  fprintf(stderr,"ERROR, no port provided\n"); 
17  exit(1); 
18 } 
19 
20 int serversock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 
21 
22 if (serversock == -1) perror("Socket"); 
23 
24 portno = atoi(argv[1]); 
25 struct sockaddr_in serveraddr, clientaddr; 
26 bzero(&serveraddr, sizeof(struct sockaddr_in)); 
27 serveraddr.sin_family = AF_INET; 
28 serveraddr.sin_addr.s_addr = htonl(INADDR_ANY); 
29 serveraddr.sin_port = htons(portno); 
30 
31 if (-1 == bind(serversock, (struct sockaddr *)&serveraddr,sizeof(struct sockaddr_in))) perror("Bind"); 
32 
33 if (-1 == listen(serversock, SOMAXCONN)) perror("Listen"); 
34 
35 FD_ZERO(&fds); 
36 FD_SET(serversock, &fds); 
37 fdmax = serversock; 
38 
39 clientaddrlen = sizeof(clientaddr); 
40 while(1) { 
41  readfds = fds; 
42  rc = select(fdmax + 1, &readfds, NULL, NULL, NULL); 
43 
44  if (rc == -1){ 
45  perror("Select"); 
46  break; 
47 } 
48 
49  for (i = serversock; i <= fdmax; i++) 
50  { 
51  if (FD_ISSET(i, &readfds)){ 
52   if (i == serversock){ 
53   if (numsocks < maxsocks){ 
54    clientsock[numsocks] = accept(serversock,(struct sockaddr *) &clientaddr, 
55     (socklen_t *)&clientaddrlen); 
56 
57    if (clientsock[numsocks] == -1) perror("Accept"); 
58    else printf("Connection accepted\n"); 
59 
60    FD_SET(clientsock[numsocks], &fds); 
61    fdmax = clientsock[numsocks]; 
62    numsocks++; 
63   } 
64   else 
65    printf("Ran out of socket space.\n"); 
66   } 
67   else 
68   { 
69   int messageLength = 100; 
70   char message[messageLength+1]; 
71   int numOfChRead, index = 0, limit = messageLength+1; 
72 
73   numOfChRead = recv(i, message, messageLength,0); 
74 
75   if(numOfChRead > 0) 
76    printf("Data Received !!! length: %d Message: %s", numOfChRead, message); 
77   else 
78    printf("Nothing read\n"); 
79   } 
80  } 
81  } 
82 } 
83 close(serversock); 
84 return 0; 
85 } 
+0

謝謝阿拉姆,現在我知道我出錯了。 – Neo

相關問題