我有 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/