2010-11-16 50 views
11

Tôi đang cố gắng tạo một máy chủ có thể được kết nối bởi nhiều máy khách. Dưới đây là mã của tôi cho đến nay:C, lập trình socket: Kết nối nhiều máy khách với máy chủ bằng cách chọn()

Chủ đầu tư:

int main(int argc, char **argv) { 

    struct sockaddr_in servaddr; 
    int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 

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

    bzero((void *) &servaddr, sizeof(servaddr)); 
    servaddr.sin_family = AF_INET; 
    servaddr.sin_port = htons(6782); 
    servaddr.sin_addr.s_addr = inet_addr(<server_ip_address>); 

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

    while(1) { 

    char message[6]; 
    fgets(message, 6, stdin); 

    message[5] = '\0'; 

    send(sock, message, 6, 0); 
    } 


    close(sock); 
} 

Server:

int main(int argc, char **argv) { 

    fd_set fds, readfds; 
    int i, clientaddrlen; 
    int clientsock[2], rc, numsocks = 0, maxsocks = 2; 

    int serversock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 
    if (serversock == -1) perror("Socket"); 

    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(6782); 

    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"); 
      FD_SET(clientsock[numsocks], &fds); 
      numsocks++; 
      } else { 
      printf("Ran out of socket space.\n"); 

      } 
     } else { 
      int messageLength = 5; 
      char message[messageLength+1]; 
      int in, index = 0, limit = messageLength+1; 

      while ((in = recv(clientsock[i], &message[index], limit, 0)) > 0) { 
      index += in; 
      limit -= in; 
      } 

      printf("%d\n", index); 
      printf("%s\n", message); 

     } 
     } 
    } 
    } 

    close(serversock); 
    return 0; 
} 

Ngay sau khi một client kết nối và gửi thông điệp đầu tiên của mình, máy chủ chỉ chạy trong một vòng lặp vô hạn, và spits ra rác từ mảng tin nhắn. recv dường như không nhận được bất cứ điều gì. Bất cứ ai có thể nhìn thấy nơi tôi đi sai?

Trả lời

4

Hai vấn đề trong mã của bạn:

  • Bạn nên làm thay vì recv(clientsock[i], ...)

  • Sau đó bạn không kiểm tra xem recv() thất bại, và do đó printf() in ra bộ đệm uninitialised message, do đó rác ở đầu ra

1

Bạn cần kiểm tra giới hạn < = 0 trong vòng đọc của bạn, trước bạn gọi là đã đọc.

1

Trong vòng lặp while cho máy chủ, hãy thay đổi mã để làm recv(i) thay vì recv(clientsocks[i]). Tôi đã triển khai mã này và nó hoạt động với sự thay đổi này.

0

tôi thay thế khác với bên dưới và nó hoạt động

} else { 
/*     int messageLength = 5; 
        char message[messageLength+1]; 
        int in, index = 0, limit = messageLength+1; 

        memset (&message[index] , 0, sizeof (message [index])); 

        while ((in = recv(i, &message[index], limit, 0)) > 0) { 
         index += in; 
         limit -= in; 
        } 

        printf("%d\n", index); 
        printf("%s\n", message); 
*/ 
        bzero(buf, sizeof(buf)); 
        if ((rval = read(i, buf, 1024)) < 0) 
         perror("reading stream message"); 
        else if (rval == 0) 
         printf("Ending connection\n"); 
        else 
         printf("-->%s\n", buf); 

       } 
+0

Bạn không cần 'bzero()'. Chỉ cần lấy tài khoản thích hợp của giá trị trả về của recv(), ví dụ trong 'printf (" ->%. * S \ n ", rval, buf);'. – EJP

0

1) Đó là một thực hành tốt để sử dụng PF_INET (giao thức gia đình) chứ không phải là
AF_INET (gia đình địa chỉ) trong quá trình tạo Socket.

2) trong vòng lặp while (1)
mỗi lần được khuyến khích để làm cho readfds của bạn trống rỗng bằng cách sử dụng FD_ZERO (& readfds). trong cuộc gọi recv() bạn nên sử dụng i thay vì clientsocks [i] bạn phải kiểm tra giá trị trả về của recv là âm (cho biết lỗi khi đọc) nếu đó là trường hợp bạn không phải in thư. trong khi in thư đảm bảo rằng máy chủ/máy chủ sẵn sàng để viết bất kỳ thứ gì cho nó mà bạn có thể thực hiện bằng cách sử dụng writefds (đối số thứ 3 của lựa chọn).

Các vấn đề liên quan