BSD сокет не работает - PullRequest
       28

BSD сокет не работает

0 голосов
/ 28 января 2012

ОБНОВЛЕНИЕ: обновлен src на основе предложений.strcat a \ n \ 0 на команду и изменение sizeof.У клиента есть «Успех» при отправке, но сервер никогда не «преуспевает» при получении.

Я приложил немало усилий, чтобы заставить работать обычный старый сокет TCP.У меня в основном простой клиент и настройка сервера.В настоящее время я ничего не получаю на моем сервере, и я получаю только 4 байта на моем клиенте («GOTY» в этом примере).

Выходные данные сервера выводят это и перемещаются:*

Вывод клиента просто блокирует и никогда не останавливается.Если я убью сервер, я получу этот вывод

Connect success
Received Response:

СЕРВЕР

int Server::update(char *getbuf)
{
    int ready = poll(pollfds, 1, 100);

    if (ready == -1)
    {
        logger.info("Poll failed");
        return FALSE;
    }

    if (pollfds[0].revents & POLLIN)
    {    
        ssize_t z;

        logger.info("Connection available");

        struct sockaddr_in client_address;
        memset(&client_address, 0, sizeof client_address);
        socklen_t alen = sizeof(client_address);

        // ACCEPT
        clientsocket = accept(serversocket, (struct sockaddr *)&client_address, &alen);
        if(!clientsocket)
            logger.fail("Accept Fail");

        // READ
        z = recv(clientsocket, getbuf, 512, MSG_WAITALL);
        if (z < 0)
            fprintf(stderr,"receive failure\n");
        else
            fprintf(stderr,"receive succeed\n");

        getbuf[z] = 0;

        respond(getbuf);

        //closeConnection();

        logger.data("RECEIVED %s", getbuf);

        getbuf[z] = 0;

        return TRUE;
    }

    return FALSE;
}

void Server::respond(char *response)
{
    // SEND
    ssize_t z;

    z = send(clientsocket, response, strlen(response), 0);
    if (z < 0)
        fprintf(stderr,"send failure\n");
    else
        fprintf(stderr,"send succeed\n");
}

КЛИЕНТ

Я добавил код клиента.Сейчас я использую strlen, но, похоже, это не помогает.

int main(int argc, char **argv)
{
    int abort = 0;
    int port;
    in_addr_t address;
    char *command;

    ssize_t z;
    int com_socket;
    struct sockaddr_in server_address;
    struct timeval timeout;

    int opt;
    int val = 0;
    char getbuf[512];

    //Defaults
    address = inet_addr("127.0.0.1");
    port = 4949;

    //INCLUDED ARGUMENTS FROM CLI
    while((opt = getopt(argc, argv, "a:p:c:")) > 0) 
    {
        switch(opt)
        {
            case 'a':
                address = inet_addr(optarg);
                break;
            case 'p':
                port = atoi(optarg);
                break;
            case 'c':
                abort = 1;
                command = (char *)optarg;
                break;   
            default:
                fprintf(stderr, "-a IPADDRESS -p PORT -c COMMAND\n",argv[0]);
        }
    }

    // Server
    memset(&server_address, 0, sizeof(server_address));
    server_address.sin_family = AF_INET;
    server_address.sin_port = htons(port);
    server_address.sin_addr.s_addr = address;

    if (server_address.sin_addr.s_addr == INADDR_NONE)
        fprintf(stderr, "Server address failed\n");

    if(!abort)
    {
        fprintf(stderr, "No Command given\n");
        fprintf(stderr, "-a IPADDRESS -p PORT -C COMMAND\n");
        exit(0);
    }
    else
    {
        fprintf(stderr, "Address %s Port %d Command %s\n", inet_ntoa(server_address.sin_addr), port, command);
    }

    // Create com_socket
    com_socket = socket(PF_INET, SOCK_STREAM, 0);
    if (com_socket == -1)
         fprintf(stderr, "Socket failed\n");

    /*
    // Client
    struct sockaddr_in client_address;
    memset(&client_address,0,sizeof client_address);
    client_address.sin_family = AF_INET;
    client_address.sin_port = 0;
    client_address.sin_addr.s_addr = ntohl(INADDR_ANY);

    if (client_address.sin_addr.s_addr == INADDR_NONE)
        fprintf(stderr, "Client address failed\n");

    // Bind
    z= bind(com_socket, (struct sockaddr *)&client_address, sizeof (client_address));
    if ( z == -1 )
        fprintf(stderr,"Binding port\n");
    */

    timeout.tv_sec = 2; /* 2 seconds */ 
    timeout.tv_usec = 0; /* + 0 usec */

    socklen_t addrlen = sizeof(struct sockaddr_in);

    // Connect
    //z = connectWithTimeout(com_socket, (struct sockaddr *) &server_address, len_inet, &timeout);
    z = connect(com_socket, (struct sockaddr *) &server_address, sizeof(server_address));
    if(z == -1)
    {
        if(errno == EINPROGRESS)
        {
            fprintf(stderr, "EINPROGRESS non block start\n");
        }

        if(errno == EALREADY)
        {
            fprintf(stderr, "EALREADY non block subsequent request\n");
        }

        fprintf(stderr, "Connect failed\n");
    }
    else 
        fprintf(stderr, "Connect success\n");

    strcat(command, "\n\0");

    // SEND
    z = send(com_socket, command, strlen(command)+2, 0);
    if (z < 0)
        fprintf(stderr,"send failure\n");
    else
        fprintf(stderr,"send succeed\n");

    // READ
    z = recv(com_socket, getbuf, 512, MSG_WAITALL);
    if (z < 0)
        fprintf(stderr,"receive failure\n");
    else
        fprintf(stderr,"receive succeed\n");

    // Output
    fprintf(stderr, "Received Response: %s\n", getbuf);

    close(com_socket);

    exit(1);
}

Я просто не знаю, почему это не работает.Я был над этим снова и снова.

Это встроенная система Linux.

Ответы [ 3 ]

4 голосов
/ 29 января 2012

На сервере: это просто неправильно. strlen () возвращает длину строки, которая была в буфере до read () /recv().

    // READ
    z = recv(clientsocket, getbuf, strlen(getbuf), MSG_WAITALL);
    if (z < 0)
        fprintf(stderr,"receive failure\n");

Также: в response () strlen () предполагает, что ответ «строка» имеет нулевое значение. Это не так.

z = send(clientsocket, response, strlen(response), 0);

И тот же тип ошибки, по-видимому, присутствует в коде клиента.

ОБНОВЛЕНИЕ: поскольку ОП не знает, как жить без строковых функций, я проиллюстрирую, как это можно сделать.

 ... snipped ...
 // READ
    z = recv(clientsocket, getbuf, 512, MSG_WAITALL);
    if (z < 0) {
        // .... if (errno == EAGAIN) continue;
        fprintf(stderr,"receive failure %d(%s) \n"
             , errno, strerror(errno) );
        break; }

    fprintf(stderr,"receive succeed\n");

    respond(getbuf, z);

    return TRUE;
    }
return FALSE;
}

void respond(char *response, size_t siz)
{
// SEND
size_t done;
ssize_t z;

for (done = 0; done < siz; done += z) { 
    z = send(clientsocket, response+done, siz-done, 0);
    if (z < 0) {
        if (errno == EAGAIN) continue;
        fprintf(stderr,"send failure %d(%s)\n"
           , errno, strerror(errno) );
        break; }
    fprintf(stderr,"send succeed\n");
    }
}
2 голосов
/ 28 января 2012

Поскольку вы на самом деле не поделились источником своей функции «ответа», мои психические силы говорят мне, что это выглядит примерно так:

void Server::respond(char* str)
{
    send(clientsock, str, sizeof(str), 0);
}

Таким образом, "sizeof (str)" оценивается как 4, потому что это размер указателя на вашем компьютере. Это согласуется с тем, что клиент получает «GOTY» (первые 4 байта сообщения, которое вы намеревались отправить).

Измените его на следующее:

void Server::respond(char* str)
{
    send(clientsock, str, strlen(str), 0);
}

Кроме того, вы никогда не должны предполагать, что эти send и recv вернут значение, равное количеству данных, которые вы ожидали отправить или получить. Следовательно, вы должны зацикливаться на неблокирующих вызовах для отправки / получения до тех пор, пока все сообщение не будет отправлено или использовано.

0 голосов
/ 28 января 2012

Операции отправки на сокетах часто буферизуются, поэтому возможно, что ваша функция ответа не сбрасывает все эти данные.Попробуйте выполнить операцию сброса в конце respond(), чтобы получить дополнительные данные.

Мне кажется, что вы видите блокирующее поведение, вы можете захотеть посмотреть, как блокирование / неблокирование влияет на сокеты.

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