c++ - 通过 WinSocket 客户端/服务器应用程序重用套接字

标签 c++ c windows sockets

我有 2 个简单的应用程序,一个客户端和一个服务器。客户端连接到服务器,服务器向客户端发送数据。在客户端应用程序的主循环中,每次我想接收另一条信息时,我都会关闭套接字并创建一个新套接字。它有效,但它看起来不适合我。这是正确的吗?我真的需要每次都关闭并重新打开套接字,还是有其他方法可以做到这一点?

客户:

    int main(){
    DWORD id;
    SOCKET s;
    struct sockaddr_in sa;
    WSADATA wsas;
    WORD wersja;
    int recv_size;
    LPTHREAD_START_ROUTINE WINAPI funkcja = getCommend;

    watek = CreateThread(NULL, 0, funkcja, 0, 0, &id);



    wersja = MAKEWORD(2, 0);
    WSAStartup(wersja, &wsas);


    memset((void *)(&sa), 0, sizeof(sa));
    sa.sin_family = AF_INET;
    sa.sin_port = htons(PORT);
    sa.sin_addr.s_addr = inet_addr("25.62.229.110");

    int result;
    s = socket(AF_INET, SOCK_STREAM, 0);
    result = connect(s, (struct sockaddr FAR *) &sa, sizeof(sa));
    if (result == SOCKET_ERROR)
    {
        printf("\nBłąd połączenia!");
        return 1;
    }

    int a;
    if ((recv_size = recv(s, server_reply, SIZE, 0)) == SOCKET_ERROR)
    {
        printf("recv failed\n");
    }
    else{
        while (result != SOCKET_ERROR){
            //printf("%s\n", server_reply);     
            closesocket(s);
            Sleep(1000);
            s = socket(AF_INET, SOCK_STREAM, 0);
            result = connect(s, (struct sockaddr FAR *) &sa, sizeof(sa));
            if (result == SOCKET_ERROR){
                break;
            }
            result = recv_size = recv(s, server_reply, SIZE, 0);
        }
    }
    getchar();
    closesocket(s);
    TerminateThread(watek, NULL);
    WSACleanup();
    return 1;
}

服务器:

int main(){
DWORD id;
SOCKET s, new_socket;
LPTHREAD_START_ROUTINE WINAPI funkcja = getCommend;
struct sockaddr_in sa, sc;
WSADATA wsas;
int c;
watek = CreateThread(NULL,0,funkcja,0,0,&id);

WSAStartup(MAKEWORD(1, 1), &wsas);

s = socket(AF_INET, SOCK_STREAM, 0);

//memset((void *)(&sa), 0, sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_port = htons(PORT);
sa.sin_addr.s_addr = htonl(INADDR_ANY);
bind(s, (struct sockaddr FAR*)&sa, sizeof(sa));
listen(s, 5);
puts("Czekam na polaczenie...");
c = sizeof(struct sockaddr_in);
while ((new_socket = accept(s, (struct sockaddr *)&sc, &c)) != INVALID_SOCKET)
{
    //puts("polaczenie zaakceptowane");
    send(new_socket, message, strlen(message), 0);
}
if (new_socket == INVALID_SOCKET)
{
    printf("Nie udane połaczenie, blad nr : %d", WSAGetLastError());
    return 1;
}
TerminateThread(watek, NULL);   
getchar();
}

最佳答案

嗯,这里有些东西不是很常见。

首先,您通常用英文命名您的变量,而不是用拉丁字母书写的其他语言。我可能会为此投反对票,但这是普遍做法是有原因的。

其次,我更愿意使用 C++ 标准而不是特定于操作系统的 API。 为什么不用 std::thread 而不是 WinApi 线程呢?它更加简单、简短和优雅。

第三,您的代码是 100% 程序化的。您没有标准的 C++ 套接字类,但这并不意味着您不能(或不应该)编写自己的套接字类,以优雅的方式处理创建、绑定(bind)、发送和接收功能。

第四,s 不是变量的好名称,即使 MSDN 示例如此。 acceptingSocket 可能是。

关于您的实际问题: 这里有很多选择,我能想到的 3 个:
1) 不关闭套接字并在 while 循环内继续接收数据。
优点:易于编写。当服务器有新数据时,客户端会立即获取它。 缺点:当您的服务器每次有更多的少数连接时,这不是一个好方法,因为那样它会崩溃。

2)让服务器打包数据。然后客户端以预定义的时间间隔打开一个连接,一次请求所有累积的数据并接收它。
优点:三者中最节省 CPU 资源 选项。 缺点:您的客户不会立即获取数据,而是在预定义的时间间隔内获取数据

3) 让客户端在每个 session 开始时将本地 IP 和端口发送到服务器。然后让客户端在本地主机上保留一个有界套接字等待连接。每次服务器有新的东西要告诉客户端时——它只是使用保存的 IP 和端口连接到客户端,发送数据并关闭连接。然后客户端返回等待新的连接。这样
优点:在这种情况下,服务器每次都会有尽可能少的连接,如果您想让服务器为许多客户端提供服务,这是一件好事。 缺点:重量实际上落在了客户身上,在许多情况下这不是最好的做法。

关于c++ - 通过 WinSocket 客户端/服务器应用程序重用套接字,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30219088/

相关文章:

php - 将 PEAR 包的本地版本指向开发路径?

python - Tensorflow Windows 访问文件夹被拒绝 :"NewRandomAccessFile failed to Create/Open: Access is denied. ; Input/output error"

c++ - Media Foundation 网络摄像头视频 H264 编码/解码在播放时产生伪像

c++ - 使用类型转换将 C 库包装在 C++ 类中

c++ - 了解位运算及其效果

c - 为什么 setjmp 传统上保存寄存器?

c++ - 抑制 SSL 错误

c - 在 C 中使用预训练的 pytorch 模型?

c++ - 获取磁盘转速示例代码

windows - Windows 快速启动命令行上的 FFMPEG,带或不带 +