Не удается получить или отправить весь пакет при программировании сокетов с использованием C - PullRequest
0 голосов
/ 24 июля 2011

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

Теперь я не уверен, является ли проблема на отправляющей или принимающей стороне. Я догадываюсь, что что-то не так на моей стороне Может ли кто-нибудь помочь в проверке моего предположения?

Код клиента:

int main(int argc, char *argv[])
{
    int sockfd, portno, n;
    struct sockaddr_in serv_addr;
    struct hostent *server;
    data_struct client_data;
    struct packet
    { 
        long int srcID;
        long int destID;
        int pver;
        int profiles;
        int length;
        long int data;
    };


    if (argc < 3) {
        fprintf(stderr,"usage: %s hostname port\n", argv[0]);
        exit(0);
    }
    portno = atoi(argv[2]); //Convert ASCII to integer
    sockfd = socket(AF_INET, SOCK_STREAM, 0); // socket file descriptor

    if (sockfd < 0) 
        error("ERROR DETECTED !!! Problem in opening socket\n");

    server = gethostbyname(argv[1]);
    if (server == NULL) {
        fprintf(stderr,"ERROR DETECTED !!!, no such server found \n");
        exit(0);
    }

    bzero((char *) &serv_addr, sizeof(serv_addr)); //clear the memory for server address

    serv_addr.sin_family = AF_INET;    
    bcopy((char *)server->h_addr, 
        (char *)&serv_addr.sin_addr.s_addr,
        server->h_length);

    serv_addr.sin_port = htons(portno);

    printf("Client 1 trying to connect with server host %s on port %d\n", argv[1], portno); 


    if (connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0) 
        error("ERROR in connection");

    printf("SUCCESS !!! Connection established \n");

    char buffer[256];
    struct packet *pkt = (struct packet *) buffer;
    char *payload = buffer + sizeof(struct packet);
    long double packet_size;



    printf("Started Creating packet\n");
    pkt->srcID = 01;
    pkt->destID = 02;
    pkt->pver = 03;
    pkt->profiles = 01;
    pkt->length = 16;
    pkt->data = 1; 2; 3; 4; 5; 6; 7; 8;
    {
        if (send(sockfd,pkt,sizeof(packet_size),0) <0)
            printf ("error\n");
        else
            printf ("packet send done");
    }

    return 0;
}

Код сервера:

int main(int argc, char *argv[])
{
    int sockfd, newsockfd, portno, clilen;
    struct sockaddr_in serv_addr, cli_addr;
    int n;
    char wish;

    long int SrcID;
    long int DestID;
    int Pver;
    int Profiles;
    long int Data;
    int Length;
    char bytes_to_receive;
    int received_bytes;
    struct packet
    { 
        long int srcID;
        long int destID;
        int pver;
        int profiles;
        int length;
        long int data;
    };

    if (argc < 2) {
        fprintf(stderr,"usage: %s port_number1",argv[0]);
        exit(1);
    }
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) 
        error("ERROR DETECTED !!! Problem in opening socket");

    bzero((char *) &serv_addr, sizeof(serv_addr));
    portno = atoi(argv[1]);

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

    if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) 
        error("ERROR DETECTED !!! There was a problem in binding");

    listen(sockfd, 10);
    clilen = sizeof(cli_addr);
    printf("Server listening on port number %d...\n", serv_addr.sin_port); 
    newsockfd = accept(sockfd,(struct sockaddr *) &cli_addr, &clilen);

    if (newsockfd < 0) 
        error("ERROR DETECTED !!! the connection request was not accepted");

    char buffer[256];
    struct packet *pkt = (struct packet *) buffer;
    char *payload = buffer + sizeof(struct packet);
    long double packet_size;

    bytes_to_receive = sizeof(packet_size);
    received_bytes = 0;
    int rc =0;


    while ((rc = recv(newsockfd,pkt,sizeof(packet_size),0)) > 0)
    {
        received_bytes+=rc;
        SrcID = pkt->srcID;
        DestID = pkt->destID;
        Pver = pkt->pver ;
        Profiles = pkt->profiles;
        Length = pkt->length;
        Data = pkt->data;
        printf("Data Received from Client_1 are :\n");
        printf("Source ID: %ld\n", SrcID);
        printf("Destination ID: %ld\n", DestID);
        printf("profile Version: %d\n", Pver);
        printf("No of Profiles: %d\n", Profiles);
        printf("Length: %d\n", Length);
        printf("data : %ld\n", Data);
    }
    if (rc == 0)
    {
        printf("Connection closed by Server\n");
        printf("Bytes received: %d\n",received_bytes);
    }

    if (rc == -1)
    {
        perror("recv");
    }
    {
        if (close(newsockfd) == -1) {
            error("Error closing connection with client 1");
        }

        printf("Connection with client 1 has been closed\n");
    }
    return 0; 

}

Вывод, который я вижу на консоли клиента:

Client Side:  Client 1 trying to connect with server host 130.191.166.230 on port 1234
SUCCESS !!! Connection established 
Started Creating packet
packet send done

и на консоли сервера я вижу:

Server Side:  Data Received from Client_1 are :
Source ID: 1
Destination ID: 2
profile Version: 0
No of Profiles: 1074462536
Length: 0
data : 0
Connection closed by Server
Bytes received: 8
Connection with client 1 has been closed

Ответы [ 4 ]

2 голосов
/ 24 июля 2011

Прежде всего

recv(newsockfd,pkt,sizeof(packet_size),0)) /* What is packet_size ? */
recv(newsockfd,pkt,sizeof(struct packet),0)) /* You probably mean this. */

Это может решить ваши проблемы, но есть несколько проблем с тем, как вы используете TCP-сокеты.

Но на моей стороне клиента он печатает, что отправил все

Где? Я не вижу, чтобы вы на самом деле проверяли количество отправленных байтов. send(2) может вернуться после отправки меньше, чем вы просили.

Он показывает, что клиент отправил только 8 байтов, и распечатывает их.

TCP является потоковым протоколом. Вы отправляете байты, и они поступают в том же порядке. Поэтому, когда вы что-то recv(2) получаете, вы можете получить меньше (или больше, чем написали). Таким образом, верно следующее:

client:
send 100 bytes
send 400 bytes

server:
recv 50 bytes
recv 150 bytes
recv 250 bytes
recv 50 bytes

Количество вызовов send и recv не обязательно должно совпадать при использовании TCP.

2 голосов
/ 24 июля 2011

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

bool sendBuffer(SOCKET s, unsigned char *buf, int size)
{
    while (size > 0)
    {
        int sz = send(s, buf, size,0);
        if (sz < 0) return false; // Failure
        size -= sz; // Decrement number of bytes to send
        buf += sz;  // Advance read pointer
    }
    return true; // All buffer has been sent
}

и аналогичный цикл должен быть выполнен при получении (другими словами recv может вернуть меньше байтов, чем вы запрашиваете).

Если вы не сделаете эти циклы, существует риск, что все , по-видимому, будет работать в любом случае (до размера пакета Ethernet), когда вы работаете на локальном компьютере или даже в локальной сети, но все не будет работать при работе через Интернет.

Обратите внимание, что, как указывалось в других ответах, вы просили отправить sizeof(packet_size), т. Е. Количество байтов, необходимое для хранения этой переменной, а не размер структуры.

1 голос
/ 17 сентября 2011

Существует неофициальное правило, согласно которому никому не разрешается писать любое программное обеспечение, которое использует TCP, пока оно не запомнит это предложение и не сможет полностью объяснить, что оно означает: «TCP является протоколом потока байтов, который не сохраняет границы сообщений приложения».

Это означает, что TCP гарантирует, что вы получаете только те байты, которые вы вставили, и в том же порядке.Он никоим образом не «склеивает» байты.

Прежде чем писать какой-либо код, использующий TCP, вы должны либо использовать протокол, который уже разработан (например, IMAP или HTTP), либо разработать его самостоятельно.Если вы разрабатываете его самостоятельно, вам следует написать спецификацию протокола.Он должен конкретно определять, из чего будет состоять сообщение уровня протокола на уровне байтов.В нем должно быть конкретно указано, как получатель находит концы сообщений и т. Д.

Это может показаться немного глупым для простых приложений, но, поверьте мне, это окупится массово.В противном случае почти невозможно понять, почему что-то не работает, потому что если сервер и клиент не совсем ладят друг с другом, нет арбитра, который бы сказал, что правильно.

0 голосов
/ 24 июля 2011

Я не специализируюсь на программировании сокетов, но заметил несколько вещей.Насколько я знаю, я не думаю, что вы можете легко отправлять структуры через сокеты.Возможно, вы захотите рассмотреть другой метод.

Примечание: при использовании send / recv вы также определяете размер размера пакета, а не размер структуры.

Google отправил запрос об отправкеструктуры над розетками: http://ubuntuforums.org/showthread.php?t=613906

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