Простая программа сетевого программирования - не работает - PullRequest
0 голосов
/ 06 декабря 2010

Я только начал изучать сетевое программирование. Моя первая программа очень проста: после подключения серверная программа отображает, что клиентская программа отправляет (символы). Все работает нормально, пока они не подключатся. Сначала я сделал цикл отправки, используя putc:

while((c = getc(stdin)) != '\n')
    putc(c, (FILE *) connection);

и получающий с getc:

while((c = getc((FILE *) connection)) != '\n')
    putc(c, stdout);

После подключения я получаю ошибку сегментации. Затем я попытался с помощью отправки:

while(1) {
    memset(str, null, strlen(memset));

    while(((c = getc(stdin)) != '\n') && sizeof(str) <= 100) {
        strcat(str, (char *) c);       // cast to char * is to make gcc happy
    }

    send(connection, (void *) str, sizeof(str), (int) NULL);
}

и recv:

while((stat = recv(connection,str,100,0)) != 0) {
    printf("\nReceived %d bytes of data from %s: %s", stat, client, str);
}

Теперь recv () продолжает возвращать -1, а errno устанавливается в 107. Что это значит? Где я делаю не так? Кстати, я использую Linux с gcc.

Большое спасибо за вашу помощь! :)


РЕДАКТИРОВАТЬ: Даже если я использовал getc () и putc (), я получаю соединение с socket (), затем я подключаю () (клиент). Сервер после получения соединения (с помощью socket ()) bind (), затем listen () и accept (). Извините, если я ometted.


Вот код сервера:

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

void main(int argc, char *argv[])
{
    struct addrinfo hint;
    struct addrinfo *servinfo, *count;
    struct sockaddr_storage conn_addr;
    struct sockaddr host;

    int connessione;
    int stat;
    int conn_sock;
    int conn_size;
    int success;
    int c;

    char t[INET_ADDRSTRLEN];
    char str[100];
    char *client;

    if(argc != 1 && strcmp(argv[1], "aiuto") == 0) {
        printf("%s(porta)\n",argv[0]);
        printf("porta: specifica su quale porta installarsi\n");
        exit(-1);
    }

    memset(&hint,0,sizeof hint);


    hint.ai_family = AF_INET;
    hint.ai_socktype = SOCK_STREAM;
    hint.ai_flags = AI_PASSIVE;

    if((stat = getaddrinfo(NULL, argv[1], &hint, &servinfo)) != 0)  {
        printf("\n[FATAL]: getaddrinfo: %s",gai_strerror(stat));
        exit(-1);
    }

    success = 0;

    for(count = servinfo; count != NULL; count = count->ai_next) {
        if((connessione = socket(count->ai_family, count->ai_socktype, count->ai_protocol)) <= 0)
            continue;

        if((stat = bind(connessione, count->ai_addr, count->ai_addrlen)) == 0) {
            success = 1;
            break;
        }
        else {
            continue;
        }
    }

    if(success == 0) {
        printf("\n[FATAL]: Unable to bind()!\n");
        exit(-1);
    }
    else {
        printf("\n[DEBUG]: %s: listening...", argv[0]);
    }

    servinfo = count;
    freeaddrinfo(count);

    if(listen(connessione, 20) == -1) {
        printf("\n[FATAL]: listen: %s (%d)\n", gai_strerror(errno), errno);
        close(connessione);
        exit(-1);
    }

    conn_size = sizeof(conn_addr);

    if(accept(connessione, (struct sockaddr *) &conn_addr, &conn_size) == -1) {
        printf("\n[FATAL]: accept: %s", gai_strerror(errno));
        close(connessione);
        exit(-1);
    }

    client = (char *) malloc(INET_ADDRSTRLEN * sizeof(char));
    client = inet_ntop(servinfo->ai_family, &conn_addr, t, INET_ADDRSTRLEN);

    printf("\n[DEBUG]: %s: connection accepted: %s", argv[0], client);

    while((stat = recv(connessione,str,100,0)) != 0) {
        printf("\nReceived %d bytes of data from %s: %s", stat,client, str);
    }

    printf("\n[DEBUG]: connection closed by %s\n",client);
}

И код клиента:

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

void main(int argc, char *argv[])
{
    struct addrinfo hint;
    struct addrinfo *servinfo, *count;
    struct sockaddr_storage conn_addr;
    struct sockaddr host;

    int connessione;
    int stat;
    int conn_sock;
    int conn_size;
    int success;
    int c;

    char t[INET_ADDRSTRLEN];
    char *indirizzo;
    char str[100];

    memset(&hint,0,sizeof hint);

    host.sa_family = AF_INET;
    if(inet_pton(host.sa_family, argv[1], (void *) host.sa_data) == -1) {
        printf("\n[FATAL]: pton: %s (%d)\n", gai_strerror(errno), errno);
        exit(-1);
    }

    hint.ai_family = AF_INET;
    hint.ai_socktype = SOCK_STREAM;
    hint.ai_flags = AI_PASSIVE;
    hint.ai_addr = &host;

    if((stat = getaddrinfo(argv[1], argv[2], &hint, &servinfo)) != 0)  {
        printf("[FATAL]: getaddrinfo: %s\n",gai_strerror(stat));
        exit(-1);
    }

    success = 0;
    for(count = servinfo; count != NULL; count = count->ai_next) {
        if((connessione = socket(count->ai_family, count->ai_socktype, count->ai_protocol)) == -1)
            continue;

        if(connect(connessione, count->ai_addr, count->ai_addrlen) != -1) {
            success = 1;
            break; 
        }
    }

    if(success == 0) {
        printf("\n[FATAL]: impossibile trovare l'host specificato\n");
        exit(-1);
    }

    servinfo = count;
    freeaddrinfo(count);

    indirizzo = (char *) malloc(INET_ADDRSTRLEN * sizeof(char));
    indirizzo = inet_ntop(servinfo->ai_family, &conn_addr, t, INET_ADDRSTRLEN);

    printf("\n[DEBUG]: %s: connesso a: %s\n",argv[0], indirizzo);

    while(1) {
        strcpy(str,"buffer for data to send");

        while(((c = getc(stdin)) != '\n') && sizeof(str) <= 100) {
            strcat(str, (char *) c);
        }

        send(connessione, (void *) str, sizeof(str), (int) NULL);
    }
}

В конце ...

Работает отлично! Спасибо всем. :)

Ответы [ 4 ]

5 голосов
/ 06 декабря 2010

Обычно вы не используете дескриптор FILE * для сетевого программирования.Скорее, вам нужен дескриптор сокета, возвращаемый системным вызовом socket(2).Если у вас есть его, вы можете либо connect(2) it (клиент), либо bind(2) it (сервер).Текущая связь может быть выполнена с использованием recv(2) и send(2).

Если вы действительно хотите использовать дескриптор FILE * для сетевого программирования, взгляните на библиотечную функцию fdopen(3).Он принимает дескриптор, который может быть возвращен socket(2), и возвращает дескриптор FILE *, который совместим с fread / fwrite / fprintf.

После публикации вашего полного кода наиболее значимыйошибка, которую я мог видеть, была:

if (accept(connessione, (struct sockaddr *) &conn_addr, &conn_size))

accept(2) возвращает сокет, который вы должны использовать с recv(2) / send(2), и вы отбрасываете его, используя сервервместо сокета.

1 голос
/ 06 декабря 2010

Вы делаете некоторые ошибки программирования:

1) memset (str, null, strlen (memset));

should be : memset( str ,0 ,sizeof(str) ); // if str is declared as char str[100];

2) while (((c = getc (stdin))! = '\ N') && sizeof (str) <= 100) </p>

shhould be : while(((c = getc(stdin)) != '\n') && (strlen(str) <= 100))

3) send (соединение, (void *) str, sizeof (str), (int) NULL);

should be : send(connection, (void *) str, strlen(str), (int) NULL);
1 голос
/ 06 декабря 2010

Когда вы используете приведение (например, (FILE *) connection), вы говорите компилятору: «Поверь мне, это правда».Когда вы лжете компилятору, он вам верит.

Вы солгали компилятору.connection не является указателем на структуру FILE.Ошибка сегментации - самый хороший результат, который вы можете получить, потому что он говорит вам, что что-то не так.

1 голос
/ 06 декабря 2010

Я предлагаю вам прочитать http://beej.us/guide/

Это очень хорошее руководство по программированию сокетов

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