客户端和服务器之间连续流UDP数据包的问题

时间:2015-09-22 13:49:02

标签: c++ sockets

我有一个发送数据“Hi”的客户端程序,并从服务器接收回复“Hello”。此数据传输发生200次。从客户端接收数据报的相应服务器程序,如果发送的消息为“Hi”则回复“Hello”。我在这里展示了代码。

客户计划:

void* func(void *arg){
    int dur = *((int*)arg);
    while(dur--){
        cout<<"Client sending..."<<endl;
        int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
        int s, r;
        socklen_t len = sizeof(s);
        getsockopt(sock, SOL_SOCKET, SO_SNDBUF, &s, &len);
        getsockopt(sock, SOL_SOCKET, SO_RCVBUF, &r, &len);
        cout<<"Send is "<<s<<". Recv is "<<r<<endl;
        struct sockaddr_in server_sock_addr;
        const char *server_addr = "127.0.0.1";
        char *buf = (char*)malloc(1024);
        char *mess = (char*)malloc(100);
        char *reply = (char*)malloc(100);
        bzero((char*)&server_sock_addr, sizeof(server_sock_addr));
        server_sock_addr.sin_family = AF_INET;
        server_sock_addr.sin_port = htons(5000);
        int status = inet_aton(server_addr, &server_sock_addr.sin_addr);
        strcpy(mess, "Hi");
        memcpy(buf, mess, strlen(mess));
        socklen_t addr_len = sizeof(sockaddr_in);
        sendto(sock, buf, strlen(mess), 0, (sockaddr*)&server_sock_addr, addr_len);
        cout<<"Message is sent"<<endl;
        memset(buf, 0, 1024);
        cout<<"Blocking.."<<endl;
        int bytes = recvfrom(sock, buf, 1024, 0, (sockaddr*)&server_sock_addr, &addr_len);
        memcpy(reply, buf, bytes);
        cout<<"Reply is "<<reply<<endl;
        free(reply);
        free(mess);
        free(buf);
        close(sock);
        cout<<endl<<endl;
    }
    return NULL;
}

int main(int argc, char *argv[]) {
    int status;
    int i;
    vector<pthread_t> tid;
    vector<int> ue_num;

    int num = atoi(argv[1]);
    int dur = atoi(argv[2]);
    tid.resize(num);
    ue_num.resize(num);
    for (i = 0; i < num; i++) {
        ue_num[i] = i;
        status = pthread_create(&tid[i], NULL, func, &dur);
    }
    for (i = 0; i < num; i++) {
        pthread_join(tid[i],NULL);
    }
    cout << "Requested duration has ended. Finishing the program." << endl;
    return 0;
}

服务器程序:

int main(){
    while(1){
        cout<<"**************************"<<endl;
        cout<<"SERVER started"<<endl;
        cout<<"**************************"<<endl;
        int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
        struct sockaddr_in server_sock_addr, client_sock_addr;
        const char *server_addr = "127.0.0.1";
        char *buf = (char*)malloc(1024);
        bzero((char*)&server_sock_addr, sizeof(server_sock_addr));
        server_sock_addr.sin_family = AF_INET;
        server_sock_addr.sin_port = htons(5000);
        int status = inet_aton(server_addr, &server_sock_addr.sin_addr);

        int reuse = 1;
        setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(int));
        status = bind(sock, (struct sockaddr*)&server_sock_addr, sizeof(server_sock_addr));

        socklen_t addr_len = sizeof(sockaddr_in);
        char *mess = (char*)malloc(100);
        char *reply = (char*)malloc(100);
        int bytes = recvfrom(sock, buf, 1024, 0, (sockaddr*)&client_sock_addr, &addr_len);
        memcpy(mess, buf, bytes);
        cout<<"Message is "<<mess<<" and bytes is "<<bytes<<endl;
        string str;
        str.assign(mess);
        if(str == "Hi"){
            memset(buf, 0, 1024);
            strcpy(reply, "Hello");
            memcpy(buf, reply, strlen(reply));
            status = sendto(sock, buf, strlen(reply), 0, (sockaddr*)&client_sock_addr, addr_len);
            cout<<"Send bytes is "<<status<<endl;
            if(status == 0){
                cout<<"Buffer full. Closing "<<endl;
                exit(-1);
            }
            cout<<"Reply is sent"<<endl;
        }
        free(mess);
        free(reply);
        free(buf);  
        close(sock);
    }
    return 0;
}

面临的问题:

当我运行程序时,数据传输只能在客户端和服务器之间的10次中正确发生。主要是客户端在recvfrom()调用时被阻塞,整个程序都被这个阻塞所困扰。客户端和服务器之间的数据传输应该发生200次(dur = 200)。但是在第128或第132(一些随机)数据传输实例中,会发生这种阻塞。

我试着看服务器。服务器实际上并未接收客户端发送的此数据报。当我试图在Wireshark中查看相同内容时,它显示此数据包的“目标无法访问(端口无法访问)”错误。

当以前发送的所有数据报都没有任何问题地到达目的地时,我无法理解为什么“数据报的端口无法访问错误”。请在解决此问题时提供您的意见。 UDP缓冲区大小也足够大(SND和RCV) - 25MB。

感谢。

1 个答案:

答案 0 :(得分:1)

您的客户端和服务器都会在每次迭代消息交换时打开和关闭套接字。这是非常不寻常的,特别是对于服务器而言,这可能是导致问题的原因。

特别是,客户端可以向服务器发送消息,使其在服务器关闭一个套接字和打开下一个套接字之间到达。此类消息可能会被丢弃,您观察到的“端口无法访问”错误很容易对应此问题。您的客户无法知道发生了这种情况,因为正如我们在评论中所讨论的那样,UDP无法提供可靠的交付。当然,服务器不会响应它从未收到的消息,因此客户端永远等待是徒劳的。

如果服务器至少使用相同的套接字进行所有通信,则不会出现这种情况,因此一旦发送响应(甚至之前)就准备好接收下一条消息。但请注意,通常,无限期地等待消息通过网络到达是危险的。您应该考虑在客户端的套接字上设置接收超时(查找SO_RCVTIMEO),这样如果在合理的时间内没有消息到达,则客户端不会挂起。在这种特殊情况下,它可以重试 - 这将是一个合理的客户端修复问题。