2016-07-08 3 views
2

Я пытаюсь войти в сетевое программирование и слежу за руководством по сокетам. Я написал простой Windows TCP-сервер и клиент на C, но не могу заставить их работать. Второй клиент подключается, сервер выдает ошибку «Bad file descriptor» и закрывается. Я не понимаю, как дескриптор файла, который был только что создан accept(), может быть плохим. Я провел исследование по этому вопросу и нашел людей, которые закрыли файл, прежде чем читать его, чего я не сделал.Ошибка «Bad file descriptor» в принимаемом сокете

Вот код:

SERVER

#include <stdio.h> 
#include <stdlib.h> 
#include <winsock2.h> 

int main(int argc, char *argv[]) 
{ 
    WSADATA WSAData; 
    WSAStartup(MAKEWORD(2,0), &WSAData); 

    SOCKET sock, newsock; 
    int portno, clilen; 
    char buffer[256]; 
    SOCKADDR_IN serv_addr, cli_addr; 
    int n; 

    sock = socket(AF_INET, SOCK_STREAM, 0); 

    if (sock < 0) 
    { 
     perror("Error opening socket"); 
     exit(1); 
    } 

    memset((char *) &serv_addr, 0, sizeof(serv_addr)); 
    portno = 5001; 

    serv_addr.sin_family = AF_INET; 
    serv_addr.sin_addr.s_addr = INADDR_ANY; 
    serv_addr.sin_port = htons(portno); 

    if (bind(sock, (SOCKADDR *) &serv_addr, sizeof(serv_addr)) < 0) 
    { 
     perror("Eror on binding"); 
     exit(1); 
    } 

    listen(sock, 5); 
    clilen = sizeof(cli_addr); 

    newsock = accept(sock, (SOCKADDR *) &cli_addr, &clilen); 
    if (newsock < 0) 
    { 
     perror("Error on accept"); 
     exit(1); 
    } 

    memset(buffer, 0, 256); 
    n = read(newsock, buffer, 255); 

    if (n < 0) 
    { 
     perror("Error reading from socket"); 
     exit(1); 
    } 

    printf("Here is the message : %s\n", buffer); 

    n = write(newsock, "I got your message", 18); 
    if (n < 0) 
    { 
     perror("Error writing to socket"); 
     exit(1); 
    } 

    WSACleanup(); 
    return 0; 
} 

КЛИЕНТ

#include <stdio.h> 
#include <stdlib.h> 
#include <winsock2.h> 

int main(int argc, char *argv[]) 
{ 
    WSADATA WSAData; 
    WSAStartup(MAKEWORD(2,0), &WSAData); 

    SOCKET sock; 
    int portno, n; 
    SOCKADDR_IN serv_addr; 
    HOSTENT *server; 
    char buffer[256]; 

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

    portno = atoi(argv[2]); 
    sock = socket(AF_INET, SOCK_STREAM, 0); 
    if (sock < 0) 
    { 
     perror("Error opening socket\n"); 
     exit(1); 
    } 

    server = gethostbyname(argv[1]); 

    if (server == NULL) 
    { 
     perror("Error, no such host"); 
     exit(1); 
    } 

    memset((char *) &serv_addr, 0, sizeof(serv_addr)); 
    serv_addr.sin_family = AF_INET; 
    memcpy((char *) &serv_addr.sin_addr.s_addr, (char *) server->h_addr, server->h_length); 
    serv_addr.sin_port = htons(portno); 

    if (connect(sock, (SOCKADDR *) &serv_addr, sizeof(serv_addr)) < 0) 
    { 
     perror("Error connecting to server"); 
     exit(1); 
    } 

    printf("Please enter your message : "); 
    memset(buffer, 0, 256); 
    fgets(buffer, 255, stdin); 

    n = write(sock, buffer, strlen(buffer)); 
    if (n < 0) 
    { 
     perror("Error writing to socket"); 
     exit(1); 
    } 

    memset(buffer, 0, 256); 
    n = read(sock, buffer, 255); 

    if (n < 0) 
    { 
     perror("Error reading from socket"); 
     exit(1); 
    } 

    printf("%s\n", buffer); 

    WSACleanup(); 
    return 0; 
} 

... А вот выход только в случае, если:

C:\...myfolder>server 
*here it does nothing until I start the client with "client 127.0.0.1 5001" in another window* 
Error reading from socket: Bad file descriptor 

вы видите что не так с моей треской е? Заранее спасибо за вашу помощь!

ответ

3

Я бы поставил это в комментарии, но попробуйте использовать функцию recv() вместо read(). Это связано с тем, что read() не вызывается в Socket API, поэтому, что касается Windows, дескриптор файла недействителен.

На этой же заметке у вашего клиента вы должны использовать send() вместо write().

+0

Спасибо, сейчас работает! Означает ли это, что API сокетов Windows не реализован так же, как и Linux-сокеты? Как и в, мои переменные сокета действительно файловые дескрипторы или просто идентификатор, специально предназначенный для winsock? – Toctave

+0

Является ли что-либо * действительно файловым дескриптором в Windows, или все это просто куча клоджей, притворяющаяся файловым дескриптором? –

+0

У вас есть точка. Но тогда все эти клоды являются одним и тем же типом kludge? Являются ли 'sock' и' stdin' одинаковыми, и если не так, как они отличаются? – Toctave