使用WinSocket客户端/服务器应用程序重复使用插座

reusing sockets with WinSocket client/server application

本文关键字:插座 应用程序 WinSocket 客户端 服务器 使用      更新时间:2023-10-16

我有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 failedn");
    }
    else{
        while (result != SOCKET_ERROR){
            //printf("%sn", 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();
}

好吧,这里的某些事情不是很常见。

首先,您通常用英语命名变量,而不是用拉丁字母编写的其他语言。我可能会为此感到沮丧,但这是出于某种原因的常见做法。

第二,我会在OS特定API上使用C 标准。为什么不使用std::thread而不是Winapi线程?它更简单,简短和优雅。

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

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

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

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

3)让客户在每个会话的开始中将本地IP和端口发送到服务器。然后,让客户端在本地主机上保持一个有界的套接字,等待连接。每当服务器有新的东西告诉客户端时 - 它只需使用已保存的IP和端口连接到客户端,发送数据并关闭连接即可。然后,客户返回以等待新连接。这种方式
优点:在这种情况下,服务器每次都会有尽可能少的连接,如果您将服务器打算到服务器许多客户端,那么Wich是一件好事。缺点:重量实际上落在客户上,在许多情况下,这不是最好的事情。

通常的单连接方法是:

Create socket
bind socket
Listen on socket
newsocket = accept on socket
while no accept errors
    while newsocket connected and error free
        process newsocket
    newsocket = accept on socket

可以处理多种连接。

多线程:

create thread pool
Create socket
bind socket
Listen on socket
while no errors
    newsocket = accept on socket
    hand newsocket off to thread pool for processing

一单读选择的基于

Create socket
bind socket
Listen on socket
add socket to readFD  list
while no errors
    select on readFD list
    if socket selected
        newsocket = accept on socket
        add newsocket to readFD  list
    while other sockets selected
        process other sockets