клиент-серверная программа, проблема с отправкой сообщения с клиента на сервер и наоборот с использованием TCP - PullRequest
1 голос
/ 18 сентября 2009

У меня есть небольшая программа, которая отправляет и получает данные с сервера и клиента, и наоборот. Все работает нормально, но я не вижу полученные сообщения с обеих сторон, и это всегда 0 байтов. Это не дает никакой ошибки компиляции, но не работает так, как я хотел. Можете ли вы взглянуть на это, где я делаю неправильно? Спасибо

// клиент

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

int main(int argc, char* argv[])
{
    int sockfd;

    struct addrinfo hints, *servinfo, *p;
    int rv;
    int numbytes;
    char* hostname = "localhost";
    char* server = "localhost";

    memset(&hints, 0, sizeof(hints));
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
    if ((rv = getaddrinfo(hostname, "5000", &hints, &servinfo)) != 0)
    {
        fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
        return 0;
    }


    // loop through all the results and make a socket
    for(p = servinfo; p != NULL; p = p->ai_next) 
    {
        if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) 
        {
            perror("client: socket");
            continue;
        }

        if (connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) 
        {
            close(sockfd);
            perror("client: connect");
            continue;
        }
        break;
    }
    if (p == NULL) 
    {
        fprintf(stderr, "client: failed to bind socket\n");
        return 2;
    }

    char message[] = "hi";
    if ((numbytes = send(sockfd, message, 2, 0)) == -1) 
    {
        perror("client: send");
        exit(1);
    }

    int numbytesRecv;
    char buf[100];
    if ((numbytesRecv = recv(sockfd, buf, 99, 0)) == -1) 
    {
        perror("client: recv");
        exit(1);
    }

    freeaddrinfo(servinfo);
    printf("client: sent %d bytes to %s\n", numbytes, server);
    printf("client: received %d bytes from %s\n", numbytesRecv, server);
    buf[numbytesRecv] = '\0';
    printf("client: message received is %s\n",buf);
    close(sockfd);
    return 0;
}

// сервер

#include   <stdio.h>
#include   <stdlib.h>
#include   <unistd.h>
#include   <errno.h>
#include   <string.h>
#include   <sys/types.h>
#include   <sys/socket.h>
#include   <netinet/in.h>
#include   <arpa/inet.h>
#include   <netdb.h>
#define MYPORT "5000"     // the port users will be connecting to
#define MAXBUFLEN 100
// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa)
{
     if (sa->sa_family == AF_INET) {
          return &(((struct sockaddr_in*)sa)->sin_addr);
     }
     return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
int main(void)
{
    int sockfdTCP;
    struct addrinfo hintsTCP, *servinfoTCP, *pTCP;
    int rv;
    int numbytes;
    struct sockaddr_storage their_addr;
    char buf[MAXBUFLEN];

    size_t addr_len;
    char s[INET6_ADDRSTRLEN];

    memset(&hintsTCP, 0, sizeof hintsTCP);
    hintsTCP.ai_family = AF_UNSPEC;
    hintsTCP.ai_socktype = SOCK_STREAM;
    hintsTCP.ai_flags = AI_PASSIVE;

    if ((rv = getaddrinfo(NULL, MYPORT, &hintsTCP, &servinfoTCP)) != 0) {
        fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
        return 1;
    }

    // loop through all the results and bind to the first we can for TCP socket
    for(pTCP = servinfoTCP; pTCP != NULL; pTCP = pTCP->ai_next) 
    {
        if ((sockfdTCP = socket(pTCP->ai_family, pTCP->ai_socktype,pTCP->ai_protocol)) == -1) 
        {
            perror("listener: socket");
            continue;
        }

        if (bind(sockfdTCP, pTCP->ai_addr, pTCP->ai_addrlen) == -1) 
        {
            close(sockfdTCP);
            perror("listener: bind");
            continue;
        }
        break;
    }

    if (pTCP == NULL) 
    {
        fprintf(stderr, "listener: failed to bind socket\n");
        return 2;
    }
    freeaddrinfo(servinfoTCP);

    printf("listener: waiting to recvfrom...\n");
    addr_len = sizeof their_addr;

    const int BACKLOG = 10;
    if (listen(sockfdTCP, BACKLOG) == -1) {
        perror("listen");
        exit(1);
    }

    socklen_t sin_size;
    int new_fd;
    sin_size = sizeof their_addr;
    new_fd = accept(sockfdTCP, (struct sockaddr *)&their_addr, &sin_size);
    printf("I am here\n");
    if (new_fd == -1) 
    {
        perror("accept");
    }

    if ((numbytes = recv(new_fd, buf, MAXBUFLEN, 0) == -1)) 
{
    perror("recv");
    exit(1);
}

char* msg = " hi i am server";
int numbytesSend;
if ((numbytesSend = send(new_fd, msg,strlen(msg), 0) == -1)) 
{
    perror("recv");
    exit(1);
}

inet_ntop(their_addr.ss_family,get_in_addr((struct sockaddr *)&their_addr), s, sizeof s);
printf("server: got connection from %s\n", s);

printf("listener: packet is %d bytes long\n", numbytes);
buf[numbytes] = '\0';
printf("listener: packet contains : %s\n", buf);

close(sockfdTCP);
close(new_fd);
return 0;

}

// выходной клиент

./clientTCP 
client: sent 2 bytes to localhost
client: received 0 bytes from localhost
client: message received is 

// сервер вывода

./serverTCP 
listener: waiting to recvfrom...
I am here
server: got connection from 127.0.0.1
listener: packet is 0 bytes long
listener: packet contains : 

Ответы [ 4 ]

7 голосов
/ 18 сентября 2009

Ваша проблема в этой строке на сервере:

if ((numbytes = recv(new_fd, buf, MAXBUFLEN, 0) == -1))

Должно быть:

if ((numbytes = recv(new_fd, buf, MAXBUFLEN, 0)) == -1)

Это позволит правильно назначить numbytes, что позволяет

buf[numbytes] = '\0';

делать то, что вы намерены и позволяет

printf("listener: packet contains : %s\n", buf);

распечатай что хочешь.

То же самое дело с

if ((numbytesSend = send(new_fd, msg, strlen(msg), 0) == -1))

но ошибка не проявляется в примере программы.

2 голосов
/ 18 сентября 2009

РЕДАКТИРОВАТЬ: Я только что протестировал на OS X. Ваш код работает для меня. Теперь я действительно думаю, что у вас должно быть что-то, что потребляет ваши байты. Убей свои процессы и сделай:

$ netstat -na | grep 5000

Чтобы узнать, прослушивает ли что-нибудь порт 5000. Если это так, вам нужно убить сервер.

Кроме того, убедитесь, что супер-сервер (inetd / xinetd) не создает что-то для обработки данных на порту 5000.

2 голосов
/ 18 сентября 2009

Прошло много времени с тех пор, как я занимался программированием необработанных сокетов, но я думаю, что в ваших recv() вызовах есть что-то подозрительное. IIRC, recv() блокируется, пока не будет считан полный размер буфера или соединение не будет закрыто. Так как ни один конец не посылает достаточно данных для заполнения буфера, а сокет не закрывается до тех пор, пока не вызовет recv(), я думаю, что один или оба ваших клиента / сервера должны зависнуть. Поскольку они этого не делают, происходит одно из двух. Либо сокеты настроены на неблокирующий режим, и вам необходимо настроить их для блокировки, либо что-то закрывает сокет. Извините, я не могу предложить более детальную помощь, но надеюсь, она укажет вам правильное направление. Вы также можете захотеть исследовать вызов shutdown() для использования в сокетах, чтобы не закрывать их до отправки всех данных в буфере. Не уверен, что это как-то связано с вашей проблемой.

1 голос
/ 18 сентября 2009

Похоже, вас укусил Алгоритм Нейгла . Попробуйте установить TCP_NODELAY , чтобы сразу отправлять небольшие пакеты.

Обратите внимание, что для рабочего кода вы должны выполнить профилирование, прежде чем отключить алгоритм Nagle.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...