使用C无法在套接字编程中接收或发送整个数据包

时间:2011-07-23 21:37:20

标签: c++ c sockets networking network-programming

我一直在尝试通过套接字将数据包从客户端发送到服务器。借助一些技巧,我在代码中取得了很大的进步。但是,服务器只从客户端接收八个字节并在控制台上打印它们,而在我的客户端,它似乎已经发送了所有内容。

现在我不确定问题是在发送方还是在接收方。我的预感是我的客户端出了问题。有人可以帮助验证我的假设吗?

客户代码:

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 个答案:

答案 0 :(得分:2)

首先

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时,recvTCP来电的数量不必相同。

答案 1 :(得分:2)

当您调用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可以返回比您要求的更少的字节。)

如果你不进行这些循环,那么当你在本地机器甚至局域网上工作时,显然的所有东西都会起作用(直到以太网数据包的大小),但是在互联网上工作时,事情不会奏效。

另请注意,正如其他答案所指出的那样,您要求发送sizeof(packet_size),即存储该变量所需的字节数,而不是结构的大小。

答案 2 :(得分:1)

有一个非正式的规则,任何人都不得写任何使用TCP的软件,直到他们记住这句话并完全解释它的含义:“TCP是一种不保留应用程序消息边界的字节流协议。” / p>

这意味着TCP只能确保您输入相同的字节并以相同的顺序输出。它不会以任何方式将字节“粘合”在一起。

在编写使用TCP的任何代码之前,您应该使用已经设计的协议(例如IMAP或HTTP)或自己设计一个。如果你自己设计一个,你应该写出一个协议规范。它应该具体定义协议级消息在字节级别将包含的内容。它应该具体说明接收者如何找到消息的结尾,等等。

对于简单的应用程序来说,这看起来有些愚蠢,但相信我,它会大量回报。否则,几乎不可能弄清楚为什么事情不起作用,因为如果服务器和客户端不相处,就没有仲裁者说出什么是正确的。

答案 3 :(得分:0)

我不专注于套接字编程,但我注意到了一些事情。据我所知,我认为你不能轻易地将结构发送到套接字上。您可能希望考虑不同的方法。

注意,当使用send / recv时,你也在确定packet_size的大小,而不是结构的大小。

谷歌搜索提出了通过套接字发送结构:http://ubuntuforums.org/showthread.php?t=613906