Winsock 绑定到同一个端口

Posted

技术标签:

【中文标题】Winsock 绑定到同一个端口【英文标题】:Winsock binding on the same port 【发布时间】:2015-03-08 19:05:54 【问题描述】:

所以我最近决定通过使用我找到的指南并搜索网络来稍微涉足 Winsock 和网络编程,但我遇到了一个我不确定应该如何解决的问题。

我正在尝试制作一个非常简单的聊天系统,我有一个可以工作的服务器程序和客户端程序,如果我只在客户端上使用(将消息发送回同一个客户端)它似乎工作得很好.当我尝试连接多个客户端时出现问题。我从 WSAgetlasterror 收到错误 10048,它似乎是作为源的绑定函数,更具体地说,我试图在同一个端口上绑定两次(每个客户端一次)。从 msdn 和论坛上环顾四周,似乎可以通过使用 setsockopt 来解决这个问题,但我不确定我应该进行哪些更改,以及这是否是最聪明的解决方案。

我的意思是我希望客户端连接到同一个端口,不是吗?客户端程序怎么知道要连接什么?还是我只是错过了什么?正如我所说,我之前没有使用 winsock 或任何其他网络编程的经验,所以我可能会以愚蠢的方式做事。

int listenOnPort(int portno, SOCKET& reciever, SOCKET s)
int error = WSAStartup(0x0202, &w);

if (error)

    cout << "Error starting WSA";
    return false; //for some reason we couldn't start Winsock


if (w.wVersion != 0x0202) //Wrong Winsock version?

    cout << "Wrong Winsock version";
    WSACleanup();
    return false;


SOCKADDR_IN addr; // The address structure for a TCP socket

addr.sin_family = AF_INET; // Address family
addr.sin_port = htons(portno); // Assign port no to this socket

//Accept a connection from any IP using INADDR_ANY
//You could pass inet_addr("0.0.0.0") instead to accomplish the 
//same thing. If you want only to watch for a connection from a 
//specific IP, specify that //instead.
addr.sin_addr.s_addr = htonl(INADDR_ANY);

s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); // Create a socket

if (s == INVALID_SOCKET)

    cout << "Couldn't create the socket";
    return false; //Don't continue if we couldn't create a //socket!!


if (bind(s, (LPSOCKADDR)&addr, sizeof(addr)) == SOCKET_ERROR)

    //We couldn't bind (this will happen if you try to bind to the same  
    //socket more than once)
    cout << "Error binding the socket";
    return false;


//Now we can start listening (allowing as many connections as possible to  
//be made at the same time using SOMAXCONN). You could specify any 
//integer value equal to or lesser than SOMAXCONN instead for custom 
//purposes). The function will not //return until a connection request is 
//made
listen(s, 1);

reciever = accept(s, NULL, NULL);
cout << "connection established\n\n";

//Don't forget to clean up with CloseConnection()!



int main()
e = WSAGetLastError();
listenOnPort(1337, r1, s1);
cout << "First Client connected\n\n";
e = WSAGetLastError();

listenOnPort(1338, r2, s2);
cout << "Second Client connected\n\n";
e = WSAGetLastError();

std::thread com1(communicate, r1, r2);
std::thread com2(communicate, r2, r1);

com1.join();
com2.join();

//system("pause");

closeConnection();

【问题讨论】:

对于 TCP,您只需创建一个被动侦听套接字并将其绑定到您的端口。客户端都连接到同一个端口,然后您在该单个被动套接字上接受这些新连接。您不需要为每个客户端打开一个被动套接字。 【参考方案1】:

您必须在服务器中有 1 个线程专门用于接受新连接。

该进程侦听新连接并为该连接分配一个新端口(在服务器中),使默认端口可用于新连接。

在服务器中,当 N 是服务器拥有的客户端数量且 1 是侦听新连接的套接字时,您将随时打开 N+1 个套接字端口。

看看这个: http://www.codeproject.com/Articles/7785/Single-Server-With-Multiple-Clients-a-Simple-C-Imp

【讨论】:

好吧,我想我明白你的意思,我似乎已经设法解决了这个问题,我只是制作了另一个处理接受的函数并从listentoport函数中删除了原来的接受,所以现在我只在开始时使用一次监听端口,只是一个问题。如果我理解正确,listen 的第二个参数是我可以在我正在使用的侦听器上拥有的连接数,但这似乎已经达到了 5 个?我是否在这里遗漏了什么,或者如果他们想要五个以上的连接该怎么办? 我不确定具体的实现。但我认为这些是队列中的待处理连接,每次您接受客户端连接时,您都会释放一个位置。因此,尽管有侦听器端口限制,您仍可以有多个连接。 它没有分配新的端口。接受的套接字使用与监听套接字相同的端口。

以上是关于Winsock 绑定到同一个端口的主要内容,如果未能解决你的问题,请参考以下文章

winsock套接字错误

WINSOCK.07.完成端口模型

Winsock API TCP/IP网络通信

如何使用 Winsock 从数据报的 IP 标头中获取源 IP 地址?

连接前的 WinSock 绑定导致 WSAEADDRNOTAVAIL - 请求的地址在其上下文中无效

Winsock编程基础2(UDP流程)