服务器套接字只能连接几次(Winsock C++)
Posted
技术标签:
【中文标题】服务器套接字只能连接几次(Winsock C++)【英文标题】:Server socket can connect few times only (Winsock C++) 【发布时间】:2013-03-13 03:07:53 【问题描述】:您好,我正在尝试用 C++ 编写服务器 winsock 以允许从 php 客户端代码进行连接。 PHP将从服务器请求数据,接收然后关闭连接。但是,2-3次连接后,再次请求PHP时,在socket_read()处挂起,页面一直在加载,服务器没有收到FD_ACCEPT事件。是因为 TIME_WAIT 连接还没有关闭吗?任何关于代码改进的建议也会很好。
SOCKET s;
SOCKADDR_IN from;
int fromLen = sizeof(from);
int port = 1111;
int listenOnPort(int portNo)
WSAData w;
int error = WSAStartup(0x0202, &w); // fill in wsa info
if(error)
printError(5);
return 0;
if(w.wVersion != 0x0202)
printError(6);
WSACleanup();
return 0;
SOCKADDR_IN addr;
SOCKET client;
addr.sin_family = AF_INET;
addr.sin_port = htons(portNo);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(s == INVALID_SOCKET)
printError(7);
return 0;
BOOL bOptVal = TRUE;
int bOptLen = sizeof (BOOL);
if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&bOptVal, bOptLen) == SOCKET_ERROR)
printError(12);
return 0;
if(bind(s, (LPSOCKADDR)&addr, sizeof(addr)) == SOCKET_ERROR)
printError(8);
return 0;
if( listen(s, 1) == SOCKET_ERROR ) //start listening
printError(13);
return 0;
//WSAAsyncSelect(s, hwnd, 1045, FD_READ | FD_CONNECT | FD_CLOSE | FD_ACCEPT);
cout << "Ready to accept connection, listening on port " << portNo << endl;
CreateThread(0,0, &listenForEvents, NULL, 0, 0);
//listenForEvents();
return 1; //ok
DWORD WINAPI listenForEvents(void* lp)
HANDLE sockEv=CreateEvent(NULL,TRUE,FALSE,NULL);
if(WSAEventSelect(s,sockEv,FD_ACCEPT|FD_CONNECT| FD_READ | FD_CLOSE )==SOCKET_ERROR)
printError(9);
for(;;)
if(WSAWaitForMultipleEvents(1,&sockEv,FALSE,INFINITE,FALSE)!=WSA_WAIT_EVENT_0)
printError(10);
WSANETWORKEVENTS wsaEvents=0;
if(WSAEnumNetworkEvents(s,sockEv,&wsaEvents)==SOCKET_ERROR)
printError(11);
if((wsaEvents.lNetworkEvents & FD_ACCEPT)==FD_ACCEPT)
SOCKET tempSock = accept(s, (struct sockaddr*) &from, &fromLen);
s = tempSock; //switch our old socket to the new one
char acceptAddr[100];
char* msg = "Connnection from [%s] accepted.";
//sprintf(acceptAddr, msg, inet_ntoa(from.sin_addr) );
sprintf_s(acceptAddr, strlen(msg) + 100, msg, inet_ntoa(from.sin_addr));
cout << acceptAddr << endl;
hasClient = true;
else if((wsaEvents.lNetworkEvents & FD_READ) == FD_READ)
char buffer[1000];
memset(buffer, 0, sizeof(buffer));
recv(s, buffer, sizeof(buffer)-1, 0);
receiveAction(string(buffer));
//cout << buffer << endl;
else if((wsaEvents.lNetworkEvents & FD_CLOSE) == FD_CLOSE)
shutdown(s, SD_BOTH );
closesocket(s);
cout << "socket closed" << endl;
startServer(); // start server again
return 0;
else if(wsaEvents.lNetworkEvents==0)
printError(14);
cout << "lNetworkEvents==0" << endl;
void startServer()
listenOnPort(port);
这是 PHP 代码。
/* Get the port for the WWW service. */
// $service_port = getservbyname('www', 'tcp');
$service_port = "1111";
/* Get the IP address for the target host. */
$address = "192.168.3.5";
/* Create a TCP/IP socket. */
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if ($socket === false)
echo "socket_create() failed: reason: " . socket_strerror(socket_last_error()) . "\n";
die();
else
//echo "OK.\n";
//echo "Attempting to connect to '$address' on port '$service_port'...";
$result = socket_connect($socket, $address, $service_port);
if ($result === false)
echo "socket_connect() failed.\nReason: ($result) " . socket_strerror(socket_last_error($socket)) . "\n";
die();
else
//echo "OK.\n";
$out = '';
//echo "Sending HTTP HEAD request...";
$result = socket_write($socket, $json, strlen($json));
if ($result === false)
echo "socket_connect() failed.\nReason: ($result) " . socket_strerror(socket_last_error($socket)) . "\n";
die();
else
//echo "OK.\n";
echo socket_read($socket, 2048);
// while ($out = socket_read($socket, 2048))
// echo $out;
//
socket_close($socket);
【问题讨论】:
【参考方案1】:终于成功了,我对winsock函数、流程等不太了解。这是工作的。关键是让侦听器套接字保持活动状态,然后将客户端/接受的套接字存储在另一个地方。
SOCKET sock[2];
SOCKADDR_IN from;
int fromLen = sizeof(from);
int port = 1111;
int listenOnPort(int portNo)
WSAData w;
int error = WSAStartup(0x0202, &w); // fill in wsa info
if(error)
printError(5);
return 0;
if(w.wVersion != 0x0202)
printError(6);
WSACleanup();
return 0;
SOCKADDR_IN addr;
SOCKET client;
addr.sin_family = AF_INET;
addr.sin_port = htons(portNo);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
sock[0] = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(sock[0] == INVALID_SOCKET)
printError(7);
return 0;
BOOL bOptVal = TRUE;
int bOptLen = sizeof (BOOL);
if(setsockopt(sock[0], SOL_SOCKET, SO_REUSEADDR, (char *)&bOptVal, bOptLen) == SOCKET_ERROR)
printError(12);
return 0;
if(bind(sock[0], (LPSOCKADDR)&addr, sizeof(addr)) == SOCKET_ERROR)
printError(8);
return 0;
if( listen(sock[0], 1) == SOCKET_ERROR ) //start listening
printError(13);
return 0;
//WSAAsyncSelect(sock[0], hwnd, 1045, FD_READ | FD_CONNECT | FD_CLOSE | FD_ACCEPT);
cout << "Ready to accept connection, listening on port " << portNo << endl;
CreateThread(0,0, &listenForEvents, NULL, 0, 0);
//listenForEvents();
return 1; //ok
DWORD WINAPI listenForEvents(void* lp)
HANDLE sockEv[2];
sockEv[0]=CreateEvent(NULL,TRUE,FALSE,NULL);
sockEv[1]=CreateEvent(NULL,TRUE,FALSE,NULL);
if(WSAEventSelect(sock[0],sockEv[0],FD_ACCEPT|FD_CONNECT|FD_CLOSE )==SOCKET_ERROR)
printError(9);
for(;;)
int index = WSAWaitForMultipleEvents(2,sockEv,FALSE,INFINITE,FALSE);
//if(index != WSA_WAIT_EVENT_0)
// printError(10);
index -= WSA_WAIT_EVENT_0;
WSANETWORKEVENTS wsaEvents=0;
if(WSAEnumNetworkEvents(sock[index],sockEv[index],&wsaEvents)==SOCKET_ERROR)
printError(11);
if((wsaEvents.lNetworkEvents & FD_ACCEPT)==FD_ACCEPT)
sock[index+1]= accept(sock[index], (struct sockaddr*) &from, &fromLen);
//s = clientSock; //switch our old socket to the new one
if(WSAEventSelect(sock[index+1], sockEv[index+1], FD_READ|FD_CLOSE ) == SOCKET_ERROR)
printError(15);
char acceptAddr[100];
char* msg = "Connnection from [%s] accepted.";
//sprintf(acceptAddr, msg, inet_ntoa(from.sin_addr) );
sprintf_s(acceptAddr, strlen(msg) + 100, msg, inet_ntoa(from.sin_addr));
cout << acceptAddr << endl;
hasClient = true;
else if((wsaEvents.lNetworkEvents & FD_READ) == FD_READ)
char buffer[1000];
memset(buffer, 0, sizeof(buffer));
recv(sock[index], buffer, sizeof(buffer)-1, 0);
receiveAction(string(buffer));
else if((wsaEvents.lNetworkEvents & FD_CLOSE) == FD_CLOSE)
shutdown(sock[index], SD_BOTH );
closesocket(sock[index]);
if(getDebug())
cout << "socket closed" << endl;
//startServer(); // start server again
//return 0;
else if(wsaEvents.lNetworkEvents==0)
printError(14);
cout << "lNetworkEvents==0" << endl;
【讨论】:
以上是关于服务器套接字只能连接几次(Winsock C++)的主要内容,如果未能解决你的问题,请参考以下文章