iocp socket close_wait status, how to fix it? - c++
It is not easy to write a iocp console server,socket pool and thread pool works well,but after some times leater, the server can not connect again,though nothing wrong happens, why? I use procexp_16.05.1446001339.exe to check the process properties, I found lots of close_wait status, after some times again, close_wait status disappears, but the server still can not connect.Why is that? And how to fix it ?
#include "stdafx.h"
#include "Winsock2.h"
#include "Windows.h"
#include "Winbase.h"
#include "tlhelp32.h"
#include "tchar.h"
#include "Psapi.h"
#include "Winternl.h"
#include "Shlwapi.h"
#include "mstcpip.h"
#include
#include "ws2tcpip.h"
#include "time.h"
#pragma comment( lib, "Kernel32.lib" )
#pragma comment( lib, "Shlwapi.lib" )
#pragma comment( lib, "Psapi.lib" )
#pragma comment( lib, "Winmm.lib" )
#pragma comment( lib, "Ws2_32.lib" )
#define DATA_BUFSIZE 10240
#define OP_ACCEPT 1
#define OP_RECV 2
#define OP_SEND 3
#define OP_DIS 4
#define OP_ONACCEPT 5
//iocp struct
struct iocp_overlapped{
OVERLAPPED m_ol; //
int m_iOpType; //do type
SOCKET m_skServer; //server socket
SOCKET m_skClient; //client
DWORD m_recvBytes; //recv msg bytes
char m_pBuf[DATA_BUFSIZE]; //recv buf
WSABUF m_DataBuf; //recv data buf
int m_recv_timeout; //recv timeout
int m_send_timeout;
SOCKADDR_IN m_addrClient; //client address
SOCKADDR_IN m_addrServer; //server address
int m_isUsed; //client is active 1 yes 0 not
time_t m_active; //the last active time
int m_isCrashed; //is crashed? 0 not 1 yes
int m_online; //is online 1 yes 0 not
int m_usenum; //
//void (*handler)(int,struct tag_socket_data*); data->handler(res, data);
};
static SOCKET m_sock_listen = INVALID_SOCKET; //the server listen socket
class WingIOCP{
private:
char* m_listen_ip; //listen ip
int m_port; //listen port
int m_max_connect; //max connection
int m_recv_timeout; //recv timeout
int m_send_timeout; //send timeout
unsigned long* m_povs; //clients
//iocp worker
static VOID CALLBACK worker(
DWORD dwErrorCode,
DWORD dwBytesTrans,
LPOVERLAPPED lpOverlapped
);
//accept ex
static BOOL accept(
SOCKET sAcceptSocket,
PVOID lpOutputBuffer,
DWORD dwReceiveDataLength,
DWORD dwLocalAddressLength,
DWORD dwRemoteAddressLength,
LPDWORD lpdwBytesReceived,
LPOVERLAPPED lpOverlapped
);
//disconnect a client socket and reuse it
static BOOL disconnect( SOCKET client_socket , LPOVERLAPPED lpOverlapped , DWORD dwFlags = TF_REUSE_SOCKET , DWORD reserved = 0);
//event callbacks
static void onconnect( iocp_overlapped *&povl );
static void ondisconnect( iocp_overlapped *&povl );
static void onclose( iocp_overlapped *&povl );
static void onrecv( iocp_overlapped *&povl );
static void onsend( iocp_overlapped *&povl );
static void onrun( iocp_overlapped *&povl, DWORD errorcode, int last_error );
static void onaccept(iocp_overlapped *&pOL);
public:
WingIOCP(
const char* listen = "0.0.0.0",
const int port = 6998,
const int max_connect = 10,
const int recv_timeout = 3000,
const int send_timeout = 3000
);
~WingIOCP();
BOOL start();
void wait();
};
/**
* # construct
*/
WingIOCP::WingIOCP(
const char* listen, //listen ip
const int port, //listen port
const int max_connect, //max connect
const int recv_timeout,//recv timeout in milliseconds
const int send_timeout //send timeout in milliseconds
)
{
this->m_listen_ip = _strdup(listen); //listen ip
this->m_port = port; //listen port
this->m_max_connect = max_connect; //max connect
this->m_recv_timeout = recv_timeout; //recv timeout
this->m_send_timeout = send_timeout; //send timeout
this->m_povs = new unsigned long[max_connect];//clients
}
/**
* # destruct
*/
WingIOCP::~WingIOCP(){
if( this->m_listen_ip )
{
free(this->m_listen_ip );
this->m_listen_ip = NULL;
}
if( this->m_povs )
{
delete[] this->m_povs;
this->m_povs = NULL;
}
if( m_sock_listen != INVALID_SOCKET )
{
closesocket( m_sock_listen );
m_sock_listen = INVALID_SOCKET;
}
WSACleanup();
}
/**
*#wait
*/
void WingIOCP::wait(){
while( true ){
Sleep(10);
}
}
//event callbacks
void WingIOCP::onconnect( iocp_overlapped *&pOL ){
printf("%ld onconnect\r\n",pOL->m_skClient);
pOL->m_online = 1;
pOL->m_active = time(NULL);
if( setsockopt( pOL->m_skClient, SOL_SOCKET,SO_UPDATE_ACCEPT_CONTEXT,(const char *)&pOL->m_skServer,sizeof(pOL->m_skServer) ) != 0 )
{
//setsockopt fail
//printf("1=>onconnect some error happened , error code %d \r\n", WSAGetLastError());
WSASetLastError(0);
return;
}
// set send timeout
if( pOL->m_send_timeout > 0 )
{
if( setsockopt( pOL->m_skClient, SOL_SOCKET,SO_SNDTIMEO, (const char*)&pOL->m_send_timeout,sizeof(pOL->m_send_timeout)) !=0 )
{
//setsockopt fail
// printf("2=>onconnect some error happened , error code %d \r\n", WSAGetLastError());
}
}
if( pOL->m_recv_timeout > 0 )
{
if( setsockopt( pOL->m_skClient, SOL_SOCKET,SO_RCVTIMEO, (const char*)&pOL->m_recv_timeout,sizeof(pOL->m_recv_timeout)) != 0 )
{
//setsockopt fail
// printf("3=>onconnect some error happened , error code %d \r\n", WSAGetLastError());
}
}
linger so_linger;
so_linger.l_onoff = TRUE;
so_linger.l_linger = 0; // without close wait status
if( setsockopt( pOL->m_skClient,SOL_SOCKET,SO_LINGER,(const char*)&so_linger,sizeof(so_linger) ) != 0 ){
// printf("31=>onconnect some error happened , error code %d \r\n", WSAGetLastError());
}
//get client ip and port
int client_size = sizeof(pOL->m_addrClient);
ZeroMemory( &pOL->m_addrClient , sizeof(pOL->m_addrClient) );
if( getpeername( pOL->m_skClient , (SOCKADDR *)&pOL->m_addrClient , &client_size ) != 0 )
{
//getpeername fail
// printf("4=>onconnect some error happened , error code %d \r\n", WSAGetLastError());
}
// printf("%s %d connect\r\n",inet_ntoa(pOL->m_addrClient.sin_addr), pOL->m_addrClient.sin_port);
//keepalive open
int dt = 1;
DWORD dw = 0;
tcp_keepalive live ;
live.keepaliveinterval = 5000; //连接之后 多长时间发现无活动 开始发送心跳吧 单位为毫秒
live.keepalivetime = 1000; //多长时间发送一次心跳包 1分钟是 60000 以此类推
live.onoff = TRUE; //是否开启 keepalive
if( setsockopt( pOL->m_skClient, SOL_SOCKET, SO_KEEPALIVE, (char *)&dt, sizeof(dt) ) != 0 )
{
//setsockopt fail
// printf("5=>onconnect some error happened , error code %d \r\n", WSAGetLastError());
}
if( WSAIoctl( pOL->m_skClient, SIO_KEEPALIVE_VALS, &live, sizeof(live), NULL, 0, &dw, &pOL->m_ol , NULL ) != 0 )
{
//WSAIoctl error
// printf("6=>onconnect some error happened , error code %d \r\n", WSAGetLastError());
}
memset(pOL->m_pBuf,0,DATA_BUFSIZE);
//post recv
pOL->m_DataBuf.buf = pOL->m_pBuf;
pOL->m_DataBuf.len = DATA_BUFSIZE;
pOL->m_iOpType = OP_RECV;
DWORD RecvBytes = 0;
DWORD Flags = 0;
int code = WSARecv(pOL->m_skClient,&(pOL->m_DataBuf),1,&RecvBytes,&Flags,&(pOL->m_ol),NULL);
int error_code = WSAGetLastError();
if( 0 != code )
{
if( WSA_IO_PENDING != error_code )
{
// printf("7=>onconnect some error happened , error code %d \r\n", WSAGetLastError());
return;
}
}
else
{
//recv complete
onrecv( pOL );
}
}
void WingIOCP::ondisconnect( iocp_overlapped *&pOL ){
// printf("ondisconnect error %d\r\n",WSAGetLastError());
WSASetLastError(0);
pOL->m_online = 0; //set offline
pOL->m_active = time(NULL); //the last active time
pOL->m_iOpType = OP_ONACCEPT; //reset status
pOL->m_isUsed = 0; //
ZeroMemory(pOL->m_pBuf,sizeof(char)*DATA_BUFSIZE); //clear buf
if( !BindIoCompletionCallback( (HANDLE)pOL->m_skClient ,worker,0) ){
// printf("BindIoCompletionCallback error %ld\r\n",WSAGetLastError());
}
//post acceptex
int error_code = accept( pOL->m_skClient,pOL->m_pBuf,0,sizeof(SOCKADDR_IN)+16,sizeof(SOCKADDR_IN)+16,NULL, (LPOVERLAPPED)pOL );
//printf("accept error %d\r\n",WSAGetLastError());
int last_error = WSAGetLastError() ;
if( !error_code && ERROR_IO_PENDING != last_error ){
}
//printf("2=>ondisconnect some error happened , error code %d \r\n================================================\r\n\r\n", WSAGetLastError());
//printf("21=>ondisconnect some error happened , error code %d \r\n================================================\r\n\r\n", WSAGetLastError());
WSASetLastError(0);
}
void WingIOCP::onaccept(iocp_overlapped *&pOL){
pOL->m_active = time(NULL); //the last active time
pOL->m_iOpType = OP_ACCEPT; //reset status
printf("%ld reuse socket real complete , error code %d \r\n", pOL->m_skClient,WSAGetLastError());
WSASetLastError(0);
}
void WingIOCP::onclose( iocp_overlapped *&pOL ){
// printf("%ld close\r\n", pOL->m_skClient);
SOCKET m_sockListen = pOL->m_skServer;
SOCKET m_client = pOL->m_skClient;
int send_timeout = pOL->m_send_timeout;
int recv_timeout = pOL->m_recv_timeout;
pOL->m_iOpType = OP_DIS;
shutdown( pOL->m_skClient, SD_BOTH );
//socket reuse
if( !disconnect( pOL->m_skClient , &pOL->m_ol ) && WSA_IO_PENDING != WSAGetLastError()) {
// printf("1=>onclose some error happened , error code %d \r\n", WSAGetLastError());
}
//printf("onclose complete %d \r\n", WSAGetLastError());
}
void WingIOCP::onrecv( iocp_overlapped *&pOL ){
pOL->m_active = time(NULL);
// printf("recv:\r\n%s\r\n\r\n",pOL->m_pBuf);
ZeroMemory(pOL->m_pBuf,DATA_BUFSIZE);
}
void WingIOCP::onsend( iocp_overlapped *&povl ){
}
void WingIOCP::onrun( iocp_overlapped *&povl, DWORD errorcode, int last_error ){}
/**
* # acceptex
*/
BOOL WingIOCP::accept(
SOCKET sAcceptSocket,
PVOID lpOutputBuffer,
DWORD dwReceiveDataLength,
DWORD dwLocalAddressLength,
DWORD dwRemoteAddressLength,
LPDWORD lpdwBytesReceived,
LPOVERLAPPED lpOverlapped
)
{
WSASetLastError(0);
if( m_sock_listen == INVALID_SOCKET || !lpOverlapped )
{
return 0;
}
GUID guidAcceptEx = WSAID_ACCEPTEX;
DWORD dwBytes = 0;
LPFN_ACCEPTEX lpfnAcceptEx;
int res= WSAIoctl( m_sock_listen, SIO_GET_EXTENSION_FUNCTION_POINTER, &guidAcceptEx,
sizeof(guidAcceptEx), &lpfnAcceptEx, sizeof(lpfnAcceptEx), &dwBytes, NULL, NULL );
if( 0 != res )
{
return 0;
}
return lpfnAcceptEx( m_sock_listen, sAcceptSocket, lpOutputBuffer, dwReceiveDataLength,
dwLocalAddressLength, dwRemoteAddressLength, lpdwBytesReceived, lpOverlapped );
}
/**
* # disconnect socket and reuse the socket
*/
BOOL WingIOCP::disconnect( SOCKET client_socket , LPOVERLAPPED lpOverlapped , DWORD dwFlags , DWORD reserved )
{
WSASetLastError(0);
if( client_socket == INVALID_SOCKET || !lpOverlapped )
{
return 0;
}
GUID GuidDisconnectEx = WSAID_DISCONNECTEX;
DWORD dwBytes = 0;
LPFN_DISCONNECTEX lpfnDisconnectEx;
if( 0 != WSAIoctl( client_socket,SIO_GET_EXTENSION_FUNCTION_POINTER,&GuidDisconnectEx,
sizeof(GuidDisconnectEx),&lpfnDisconnectEx,sizeof(lpfnDisconnectEx),&dwBytes,NULL,NULL))
{
return 0;
}
return lpfnDisconnectEx(client_socket,lpOverlapped,/*TF_REUSE_SOCKET*/dwFlags,reserved);
}
/**
* # iocp worker thread
*/
VOID CALLBACK WingIOCP::worker( DWORD dwErrorCode,DWORD dwBytesTrans,LPOVERLAPPED lpOverlapped )
{
//why here get the error code 87 ?
//printf("worker error %d\r\n",WSAGetLastError());
if( NULL == lpOverlapped )
{
//not real complete
SleepEx(20,TRUE);//set warn status
WSASetLastError(0);
return;
}
//get overlapped data
iocp_overlapped* pOL = CONTAINING_RECORD(lpOverlapped, iocp_overlapped, m_ol);
//just a test
onrun( pOL, dwErrorCode, WSAGetLastError() );
switch( pOL->m_iOpType )
{
case OP_DIS:
ondisconnect(pOL);
break;
case OP_ONACCEPT:
onaccept(pOL);
break;
case OP_ACCEPT:
{
//new client connect
onconnect( pOL );
}
break;
case OP_RECV:
{
pOL->m_recvBytes = dwBytesTrans;
//check client offline
if( 0 == dwBytesTrans || WSAECONNRESET == WSAGetLastError() || ERROR_NETNAME_DELETED == WSAGetLastError()){
onclose( pOL );
}
else
{ //recv msg from client
pOL->m_recvBytes = dwBytesTrans;
onrecv( pOL );
}
}
break;
case OP_SEND:
{
}
break;
}
WSASetLastError(0);
}
BOOL WingIOCP::start(){
do{
WSADATA wsaData;
if( WSAStartup(MAKEWORD(2,2), &wsaData) != 0 )
{
return FALSE;
}
if(LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
{
break;
}
m_sock_listen = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);
if( INVALID_SOCKET == m_sock_listen )
{
break;
}
//bind the worker thread
BOOL bReuse = TRUE;
BOOL bind_status = ::BindIoCompletionCallback((HANDLE)( m_sock_listen ), worker, 0 );
if( !bind_status )
{
break;
}
//set option SO_REUSEADDR
if( 0 != ::setsockopt( m_sock_listen, SOL_SOCKET, SO_REUSEADDR,(LPCSTR)&bReuse, sizeof(BOOL) ) )
{
//some error happened
break;
}
struct sockaddr_in ServerAddress;
ZeroMemory(&ServerAddress, sizeof(ServerAddress));
ServerAddress.sin_family = AF_INET;
ServerAddress.sin_addr.s_addr = inet_addr( this->m_listen_ip );
ServerAddress.sin_port = htons( this->m_port );
if ( SOCKET_ERROR == bind( m_sock_listen, (struct sockaddr *) &ServerAddress, sizeof( ServerAddress ) ) )
{
break;
}
if( 0 != listen( m_sock_listen , SOMAXCONN ) )
{
break;
}
//printf("1=>start get error %d\r\n",WSAGetLastError());
WSASetLastError(0);
//socket pool
for( int i = 0 ; i m_max_connect ; i++ )
{
SOCKET client = WSASocket(AF_INET,SOCK_STREAM,IPPROTO_TCP,0,0,WSA_FLAG_OVERLAPPED);
if( INVALID_SOCKET == client )
{
continue;
}
if( !BindIoCompletionCallback( (HANDLE)client ,worker,0) )
{
closesocket(client);
continue;
}
iocp_overlapped *povl = new iocp_overlapped();
if( NULL == povl )
{
closesocket(client);
continue;
}
DWORD dwBytes = 0;
ZeroMemory(povl,sizeof(iocp_overlapped));
povl->m_iOpType = OP_ACCEPT;
povl->m_skServer = m_sock_listen;
povl->m_skClient = client;
povl->m_recv_timeout = m_recv_timeout;
povl->m_isUsed = 0;
povl->m_active = 0;
povl->m_isCrashed = 0;
povl->m_online = 0;
povl->m_usenum = 1;
int server_size = sizeof(povl->m_addrServer);
ZeroMemory(&povl->m_addrServer,server_size);
getpeername(povl->m_skServer,(SOCKADDR *)&povl->m_addrServer,&server_size);
int error_code = accept( povl->m_skClient, povl->m_pBuf, 0, sizeof(SOCKADDR_IN)+16, sizeof(SOCKADDR_IN)+16, NULL, (LPOVERLAPPED)povl );
int last_error = WSAGetLastError() ;
if( !error_code && ERROR_IO_PENDING != last_error )
{
closesocket( client );
client = povl->m_skClient = INVALID_SOCKET;
delete povl;
povl = NULL;
//printf("client=>crate error %d\r\n",WSAGetLastError());
}else{
this->m_povs[i] = (unsigned long)povl;
}
//here all the last error is 997 , means nothing error happened
//printf("client=>start get error %d\r\n",WSAGetLastError());
WSASetLastError(0);
}
//printf("last start get error %d\r\n",WSAGetLastError());
WSASetLastError(0);
return TRUE;
} while( 0 );
if( m_sock_listen != INVALID_SOCKET )
{
closesocket( m_sock_listen );
m_sock_listen = INVALID_SOCKET;
}
WSACleanup();
return FALSE;
}
int _tmain(int argc, _TCHAR* argv[])
{
WingIOCP *iocp = new WingIOCP();
iocp->start();
iocp->wait();
delete iocp;
return 0;
}
The solution to any CLOSE_WAIT issue is to close the socket. Evidently you are leaking sockets at end of stream or on an error.
Correct setsockopt usage like MS sample.
[EDIT] After some search I find this issue about AcceptEx.
Good lock.
Related
C++: char array dropping some values during send
I am facing a very odd problem in my C++ project. I have a client and a server that send char arrays of data to each other. While the initial sending/reception works well (see: Client.firstConnection() in MVE), in the following messages the client appears to drop all but the 12th through 15th chars in the array as it sends it to the server. The server then only receives this partially filled array. Example: I want to send the buffer 4_user53:6134;*0/ from the client to the server. Before sending, my variable, when printed character by character, shows 4_user53:6134;*0/ On the server side, the buffer is received but when printed character by character, shows 4;*0 On the client side, immediately after sending the buffer, the variable, when printed character by character, shows 4;*0. I do not know why these characters are disappearing. All advice is appreciated, thank you. Please find the minimal viable example below, I have done my best to annotate points of interest as well as illustrate the results of the print functions. MVE: Compiled with VS 2017, C++ 11. //Header file information // all imports: #include <cstdlib> #include <iostream> #include <map> #include <stdio.h> #include <stdlib.h> #include <string> #include <random> #include <windows.h> #include <winsock2.h> #include <ws2tcpip.h> // Global vars #define DEFAULT_BUFLEN 512 #define DEFAULT_PORT "6000" #define MAX_CONS 1 //Total No of Clients allowed //Client class Client{ bool Client::firstConnection() { WSADATA wsaData; SOCKET ConnectSocket = INVALID_SOCKET; struct addrinfo *result = NULL, *ptr = NULL, hints; int iResult; // Initialize Winsock iResult = WSAStartup( MAKEWORD( 2, 2 ), &wsaData ); if( iResult != 0 ) { printf( "WSAStartup failed with error: %d\n", iResult ); return 1; } ZeroMemory( &hints, sizeof( hints ) ); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; // Resolve the server address and port iResult = getaddrinfo( "127.0.0.1", DEFAULT_PORT, &hints, &result ); if( iResult != 0 ) { printf( "getaddrinfo failed with error: %d\n", iResult ); WSACleanup(); return 1; } // Attempt to connect to an address until one succeeds for( ptr = result; ptr != NULL; ptr = ptr->ai_next ) { // Create a SOCKET for connecting to server this->ConnectSocket = socket( ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol ); if( this->ConnectSocket == INVALID_SOCKET ) { printf( "socket failed with error: %ld\n", WSAGetLastError() ); WSACleanup(); return 1; } // Connect to server. iResult = connect( this->ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen ); if( iResult == SOCKET_ERROR ) { closesocket( this->ConnectSocket ); this->ConnectSocket = INVALID_SOCKET; continue; } break; } freeaddrinfo( result ); if( this->ConnectSocket == INVALID_SOCKET ) { printf( "Unable to connect to server!\n" ); WSACleanup(); return 1; } std::cout << "Connection to server successful!\n"; // Send an initial buffer int iResult = send( this->ConnectSocket, ( this->username ).c_str(), (int)strlen( ( this->username ).c_str() ), 0 ); //username is a perfectly fine string // -> This instance of send does NOT drop any data! <- // if( iResult == SOCKET_ERROR ) { printf( "send failed with error: %d\n", WSAGetLastError() ); closesocket( this->ConnectSocket ); WSACleanup(); return false; } return true; } bool Client::sendCommand( std::string command ) { // Send a buffer char* tmp = this->gameinfo.SerializeToArray( DEFAULT_BUFLEN ); // see below const char* send_buf = tmp; // have tried with and without const, results are the same for( int i = 0; i < (int)strlen( send_buf ); ++i ) { printf( "Buffer[%d] = [%c]\n", i, send_buf[i] ); } // Output (literally copy/pasted): /* Buffer[0] = [4] Buffer[1] = [_] Buffer[2] = [u] Buffer[3] = [s] Buffer[4] = [e] Buffer[5] = [r] Buffer[6] = [5] Buffer[7] = [3] Buffer[8] = [:] Buffer[9] = [6] Buffer[10] = [1] Buffer[11] = [3] Buffer[12] = [4] Buffer[13] = [;] Buffer[14] = [*] Buffer[15] = [0] Buffer[16] = [/] */ // This is correct and the desired output!!! ^ printf( "Sending: %s, length = %d\n", send_buf, (int)strlen( send_buf ) ); // output (literally copy/pasted): /* Sending: 4_user53:6134;*0/, length = 17 */ // This is correct and the desired output!!! int iResult = send( this->ConnectSocket, send_buf, (int)strlen( send_buf ), 0 ); for( int i = 0; i < iResult; ++i ) { printf( "Buffer[%d] = [%c]\n", i, send_buf[i] ); } //Output (literally copy/pasted): /* Buffer[0] = [ ] Buffer[1] = [ ] Buffer[2] = [ ] Buffer[3] = [ ] Buffer[4] = [ ] Buffer[5] = [ ] Buffer[6] = [ ] Buffer[7] = [ ] Buffer[8] = [ ] Buffer[9] = [ ] Buffer[10] = [ ] Buffer[11] = [ ] Buffer[12] = [4] Buffer[13] = [;] Buffer[14] = [*] Buffer[15] = [0] Buffer[16] = [ ] */ // Here we only see the values 12-15. This is not the desired output. This is the issue I want to solve. printf( "Iresult = %d\n", iResult ); //output= 17. This is correct. if( iResult == SOCKET_ERROR ) { printf( "\nSend failed with error: %d\n", WSAGetLastError() ); closesocket( ConnectSocket ); WSACleanup(); return false; } return true; } bool Client::receiveMessage() { char recvbuf[DEFAULT_BUFLEN]; int recvbuflen = DEFAULT_BUFLEN; int iResult = recv( this->ConnectSocket, recvbuf, recvbuflen, 0 ); if( iResult > 0 ) { printf("Message received OK!\n"); } else if( iResult == 0 ) { printf( "\nConnection closed\n" ); } else { printf( "\nrecv failed with error: %d\n", WSAGetLastError() ); } return true; } } int main() { std::string in = ""; int n = 0; bool rec = false; if( this->firstConnection() ) { while( in != "Q" ) { std::cin >> in; this->sendCommand( in ); while( !rec ) { rec=this->receiveMessage(); } } return this->clientClose(); } else { return false; } } //Server class Server { Server::Server() { this->currentConnections = 0; } void Server::accept_clients() { for( int i = 0; i < MAX_CONS; i++ ) { if( !this->client[i].con ) //i.e a client has not connected to this slot { if( this->accept_client( &( this->client[i] ) ) ) { //update server status this->Server_Status( CLIENT_CON ); } } } } int Server::accept_client( _client* x ) { x->i = sizeof( sockaddr ); x->cs = accept( this->ListenSocket, (sockaddr*)&x->addr, &x->i ); if( x->cs == 0 || x->cs == SOCKET_ERROR ) { printf( "SOCKET ERROR\n" ); return false; } x->con = true; FD_ZERO( &x->set ); FD_SET( x->cs, &x->set ); printf( "Client accepted \n" ); // declaring character array char char_array[DEFAULT_BUFLEN]; strcpy_s( char_array, result.c_str() ); this->send_clients( char_array ); return true; } void Server::send_clients( char* s ) { int len = (int)strlen( s ); for( int i = 0; i < MAX_CONS; i++ ) { if( this->client[i].con ) //valid slot,i.e a client has parked here { this->send_client( &( this->client[i] ), s, len ); } } } int Server::send_client( _client* x, char* buffer, int sz ) { char* send_buf; if( strchr( buffer, ';' ) == NULL ) { send_buf = x->gameinfo.SerializeToArray( DEFAULT_BUFLEN ); // see below } else { send_buf = buffer; } x->i = send( x->cs, send_buf, DEFAULT_BUFLEN, 0 ); if( x->i == SOCKET_ERROR || x->i == 0 ) { printf( "Error: disconnecting client\n" ); disconnect_client( x ); return ( false ); } else { return ( true ); } } void Server::recv_clients() { char buffer[DEFAULT_BUFLEN] = { 0 }; for( int i = 0; i < MAX_CONS; i++ ) { if( client[i].con ) //valid slot,i.e a client has parked here { try { if( !this->recv_client( &( this->client[i] ), buffer, DEFAULT_BUFLEN ) ) { //Error receiving printf( "Error receiving message from client!\n" ); } } catch( ... ) { printf( "Error\n" ); } } } } int Server::recv_client( _client* x, char* buffer, int sz ) { if( FD_ISSET( x->cs, &x->set ) ) { x->i = recv( x->cs, buffer, sz, 0 ); // checking contents for( int i = 0; i < sz+1; ++i ) { printf( "Buffer[%d] = [%c]\n", i, send_buf[i] ); } // output is (literally copy/pasted): /* Buffer[0] = [ ] Buffer[1] = [ ] Buffer[2] = [ ] Buffer[3] = [ ] Buffer[4] = [ ] Buffer[5] = [ ] Buffer[6] = [ ] Buffer[7] = [ ] Buffer[8] = [ ] Buffer[9] = [ ] Buffer[10] = [ ] Buffer[11] = [ ] Buffer[12] = [4] Buffer[13] = [;] Buffer[14] = [*] Buffer[15] = [0] Buffer[16] = [ ] */ if( x->i == 0 ) { disconnect_client( x ); return false; } std::string result = this->update( x, buffer, sz ); // returns a perfectly normal std::string - no issues here!!! // declaring character array char char_array[DEFAULT_BUFLEN]; strcpy_s( char_array, result.c_str() ); this->send_clients( char_array ); return true; } return false; } } int main() { Server gameServer = Server(); while( true ) { gameServer.accept_clients(); //Receive connections gameServer.recv_clients(); //Receive and respond to data from clients } } //Game info functions shared between client and server (only relevant ones) char* GameInformation::SerializeToArray( int buflen ) { std::string s_out = "Hello world;50*0/"; char out[512]; // more than enough space, no overflow issues here I promise strcpy_s( out, s_out.c_str() ); return out; } In case you still don't believe me, here are screenshots of the prints: Client: (while debugging I set the first iterator length to 20, that's why there are 20 values, this is of course inaccurate and I apologise for any inconvenience) Server:
The function GameInformation::SerializeToArray is bad because it is returning a pointer to non-static local array. The life of the array ends when returning from function and dereferencing pointers pointing at elements of the array after returning is illegal. Instead of that, you should allocate a buffer on the heap and return a pointer to that. //Game info functions shared between client and server (only relevant ones) char* GameInformation::SerializeToArray( int buflen ) { std::string s_out = "Hello world;50*0/"; char* out = new char[512]; // more than enough space, no overflow issues here I promise strcpy_s( out, 512, s_out.c_str() ); return out; } Note that now you should free (via delete[]) the returned array after finished using that. Another option is returning std::vector instead of plain array. This will eliminate needs to manually management memory regions. //Game info functions shared between client and server (only relevant ones) std::vector<char> GameInformation::SerializeToArray( int buflen ) { std::string s_out = "Hello world;50*0/"; std::vector<char> out(512); // more than enough space, no overflow issues here I promise strcpy_s( &out[0], 512, s_out.c_str() ); return out; } And the caller in this case will be like this: // Send a buffer std::vector<char> tmp = this->gameinfo.SerializeToArray( DEFAULT_BUFLEN ); const char* send_buf = tmp.data(); The declaration of GameInformation::SerializeToArray should also be changed to return std::vector<char> in this case.
use timer to close server as well as connection
Issues: 1) To close down the server say after 10 sec if request to accept connection has not come from client. 2) Also broke the connection and close the server if no packets has been received from the client say for 10 secs . Overview : I have an application which opens RFcomm server connection and DUT( Device under test) connects to it. Once connection with Rfcomm has been established then the application creates SCO server and listen for sco connection. All I wanted is to close the server if no request for conncection has been received on RFcomm or SCO side . Also close the connection and server if DUT has failed to send any packets with 10 secs. As pointed out by forum member to me to use KEEPALIVE but my application crashes as I think KEEPALIVE does not work with SOL_SCO. Below are the sample code int ScoServerListen(void( *handler )( int sco_listen_sock ) ) { printf(" start sco_listen connection\n" ); struct sockaddr_sco addr; struct sco_conninfo conn; socklen_t optlen; int sco_listen_sock, sco_accept_sock; char ba[18]; int *new_sock; // Create socket // sco_listen_sock = socket( PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO ); if( sco_listen_sock < 0 ) { printf( "Can't create socket: %s (%d)\n", strerror( errno ), errno ); exit(1); } printf(" start sco_listen connection .. socket created.... yeeee \n" ); // Bind to local address // memset( &addr, 0, sizeof( addr ) ); addr.sco_family = AF_BLUETOOTH; bacpy( &addr.sco_bdaddr, &bdaddr ); if( bind( sco_listen_sock, ( struct sockaddr * ) &addr, sizeof( addr ) ) < 0) { printf("Can't bind socket: %s (%d)\n", strerror(errno), errno ); goto error; } printf(" start sco_listen connection .. bind done.... yeeee \n" ); // Listen for connections // if( listen( sco_listen_sock, no_of_connect_listen ) ) { printf("Can not listen on the socket: %s (%d)\n", strerror( errno ), errno ); goto error; } std::cout << "Waiting for connection ...\n"; while( 1 ) { memset(&addr, 0, sizeof(addr)); optlen = sizeof(addr); sco_accept_sock = accept( sco_listen_sock, ( struct sockaddr * ) &addr, &optlen ); if( sco_accept_sock < 0 ) { printf("Accept for SCO failed: %s (%d)\n", strerror( errno ), errno ); goto error; } //using socketoption //Get connection information // memset( &conn, 0, sizeof( conn ) ); optlen = sizeof( conn ); if( getsockopt( sco_accept_sock, SOL_SCO, SCO_CONNINFO, &conn, &optlen ) < 0) { printf( "Can't get SCO connection information: %s (%d)\n", strerror(errno), errno); close( sco_accept_sock ); goto error; } ba2str( &addr.sco_bdaddr, ba ); printf( "Connect from %s [handle %d, class 0x%02x%02x%02x]",ba, conn.hci_handle, conn.dev_class[2], conn.dev_class[1], conn.dev_class[0]); pthread_t sniffer_thread; new_sock = (int*)malloc(1); *new_sock = sco_accept_sock; if( pthread_create( &sniffer_thread, NULL, connection_handler, (void*)new_sock )< 0 ) { perror(" could not create thread"); return 1; } ( void )pthread_join( sniffer_thread, NULL ); puts (" handler assigned"); close( sco_accept_sock ); close( sco_listen_sock ); printf( "Disconnect"); //close( sco_listen_sock ); exit(0); } return 0; error: close( sco_listen_sock ); exit( 1 ); } void *connection_handler( void *socket_desc) { // get socket descriptor int sock = *(int*)socket_desc; int read_size; char*message, message_client[ 200 ]; //receive messgae from client while( read_size = recv( sock, message_client, 200, 0 ) > 0 ) { printf(" very good\n"); } if( read_size == 0 ) { printf("clinet disconnected \n"); fflush( stdout); } else if( read_size == -1 ) { printf("received failed \n"); perror( " recv fialed"); } free( socket_desc ); int rel = 200; pthread_exit(&rel); return 0; } int RfcommListen( uint8_t channel ) { printf(" rfcomm --> we are at that start\n"); int rfcomm_sock; // socket descriptor for local listener int rfcomm_client; // socket descriptor for remote client socklen_t len = sizeof(struct sockaddr_rc); struct sockaddr_rc remote; // local rfcomm socket address struct sockaddr_rc local; // remote rfcomm socket address char pszremote[20]={ 0 }; // initialize a bluetooth socket rfcomm_sock = socket( PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM ); if( rfcomm_sock < 0 ) { printf( "RFComm socket Error \n" ); return BtSocketError; } memset(&local, 0, sizeof(local)); local.rc_family = AF_BLUETOOTH; local.rc_bdaddr = *BDADDR_ANY_INITIALIZER; local.rc_channel = channel; // bind the socket to a bluetooth device if( bind( rfcomm_sock, ( struct sockaddr * )&local, sizeof( local ) ) < 0 ) { close( rfcomm_sock ); return BtSocketError; } printf(" rfcomm --> bind successful\n"); // set the listening queue length if( listen( rfcomm_sock, 1 ) < 0 ) { printf(" we are in SCO Configure where listen failed \n"); return BtSocketError; } printf("accepting connections on channel: %d\n", channel); // accept incoming connections; this is a blocking call rfcomm_client = accept( rfcomm_sock, (struct sockaddr *)&remote, &len ); ba2str( &remote.rc_bdaddr, pszremote ); printf("received connection from: %s\n", pszremote); // turn off blocking if ( fcntl( rfcomm_client, F_SETFL, O_NONBLOCK ) < 0 ) { printf("Failed non blocking\n"); return BtSocketError; } // return the client socket descriptor return rfcomm_client; }
Sockets will just die and not reconnect after some time
I wrote this module for a chat room, and whenever the socket dies it should try to reconnect. However, I've noticed that after around 10 or 15 minutes, the socket will stop trying to reconnect. Why could this happen? My code is as follows: bool Socket::Connection::_connect(int delay_ms) { closesocket(sock); hostEntry = gethostbyname(host); if( !hostEntry ) { //Couldn't resolve our host return false; } sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if( sock == INVALID_SOCKET ) { //Invalid socket return false; } SOCKADDR_IN serverInfo; serverInfo.sin_family = AF_INET; serverInfo.sin_addr = *(LPIN_ADDR)*hostEntry->h_addr_list; serverInfo.sin_port = htons(port); int nret = SOCKET_ERROR; while( (nret == SOCKET_ERROR) ) { nret = connect(sock, (LPSOCKADDR)&serverInfo, sizeof(struct sockaddr)); if( nret == SOCKET_ERROR ) Sleep(delay_ms); if( running == false ) return false; } return true; } void Socket::Connection::start() { u_long iMode = 1; fd_set rdevents; struct timeval tv; while( 1 ) //Outer, connection loop { if( !_connect(RECONNECT_TIME) ) continue; int nret = ioctlsocket(sock, FIONBIO, &iMode); if( nret != NO_ERROR ) continue; //if( onconnect != NULL ) //onconnect(sock); while( 1 ) //Inner, command loop { FD_ZERO( &rdevents ); FD_SET( sock, &rdevents ); tv.tv_sec = 8; tv.tv_usec = 0; nret = select(0, &rdevents, NULL, NULL, &tv); if( nret == SOCKET_ERROR ) { break; } else if( nret > 0 ) { if( FD_ISSET(sock, &rdevents) ) { char buf[1024]; nret = recv(sock, buf, 1024, 0); if( nret == 0 ) break; if( onrecv != NULL ) onrecv(sock, buf, nret); } } } } closesocket(sock); }
I fail to see the code where it says 'if socket dies, reconnect'. I do see the code that says 'when I ask you to connect, try connection in a loop till that succeeds'. They are two different things. Is there something else somewhere in your code that keeps calling start() in a loop? The command loop in the start() function would be 'breaking' out on socket errors .... and I do not see any attempt to reconnect after that break out.
writing tcp server -- buffering a stream
#include <sys/socket.h> // for socket(), bind(), listen(), accept() #include <netinet/in.h> // for PF_INET, SOCK_STREAM, IPPROTO_TCP #include <stdio.h> // for printf(), perror() #include <unistd.h> // for read(), write(), close() #include <string.h> // for bzero() #define DEMO_PORT 9723 int main( void ) { //----------------------------------------- // create an unnamed socket for the server //----------------------------------------- int sock = socket( PF_INET, SOCK_STREAM, IPPROTO_TCP ); if ( sock < 0 ) { perror( "opening stream socket" ); return -1; } printf( "\nsock=%d \n", sock ); //---------------------------------------- // construct a name for the server socket //---------------------------------------- struct sockaddr_in self; socklen_t nlen = sizeof self; bzero( &self, sizeof self ); self.sin_family = AF_INET; self.sin_port = htons( DEMO_PORT ); self.sin_addr.s_addr = htonl( INADDR_ANY ); if ( bind( sock, (sockaddr *)&self, nlen ) < 0 ) { perror( "bind failed" ); return -1; } printf( "bind succeeded port: %d\n",DEMO_PORT); //--------------------------------------------------------- // now create a connection queue and wait for some clients //--------------------------------------------------------- if ( listen( sock, 5 ) < 0 ) { perror( "listen failed" ); return -1; } printf( "listen succeeded \n" ); //--------------------------------------------------- // main loop to process clients' connection-requests //--------------------------------------------------- while ( 1 ) { sockaddr_in peer; socklen_t plen = sizeof peer; bzero( &peer, plen ); printf( "server waiting \n" ); int client = accept( sock, (sockaddr *)&peer, &plen ); if ( client < 0 ) { perror( "accept" ); break; } //--------------------------------------------- // we can now read from or write to the client //--------------------------------------------- char ch; int index = 0; char get[1024]; if ( read( client, &ch, 1 ) < 0 ) { perror( "read" ); } bool go = true; while(go){ if(ch != '/' && ch != '\r'){ printf("read: %hhd\n", ch); get[index] = ch; printf( "got stuff: %s\n", get ); index++; read(index, &ch, 1); } else { go = false; index = 0; close( client ); printf( "server responded, connection closed" ); } } //if ( write( client, &ch, 1 ) < 0 ) { perror( "write" ); break; } } close( sock ); printf( "\n" ); } the while(go) look never works and it buffers incorrectly. I do not see the pattern within the buffer or how it works. What is the correct way to do this? to except a certain amount of bytes, store them in a string, then terminate the read if it reaches a newline character?
You are passing index into the second read call where you should be passing client. This may not be your only problem but I think it is one of them.
Setting IO On A Socket
I have a C++ program where I connect to my server with a socket and I need to set the overlapped for the socket. Doing the following does not work: Function int set_wsa_proxy_client ( proxy_client *node ) { WSABUF wbuf; DWORD bytes, flags; int BufLen = 1024; wbuf.buf = node->buf; wbuf.len = node->len; flags = 0; int rr = WSARecv ( node->s , &wbuf , 1 , &bytes , &flags , &node->ov , NULL ); if (rr == FALSE) { if (WSAGetLastError() != WSA_IO_PENDING) { printf("PostRecv: WSARecv* failed: %d\n", WSAGetLastError()); if ( WSAGetLastError() == ERROR_SUCCESS ) { // this means it completed right away ... //cout << endl << "ERROR_SUCCESS - set_wsa_lobby_client completed" << endl; //cout << endl << "BYTES: " << node->len << endl; return 0; } return WSAGetLastError(); } } return 0; } Extension typedef struct OverlappedEx : OVERLAPPED { int id; } OverlappedEx; proxy_client struct struct proxy_client { // ... blah blah blah SOCKET s; OverlappedEx ov; // ... blah blah blah } Main HANDLE ServerCompletionPort = CreateIoCompletionPort ( INVALID_HANDLE_VALUE , NULL , (ULONG_PTR)NULL , 0 ); if ( ServerCompletionPort == NULL ) { fprintf( stderr , "CreateIoCompletionPort failed: %d\n" , GetLastError() ); return -1; } proxy_client *new_c = new proxy_client; memset(&new_c->ov , 0 , sizeof(new_c->ov)); new_c->ov.hEvent = ServerCompletionPort; new_c->s = (make socket) // ... Connect and other stuff ... HANDLE hrc = CreateIoCompletionPort( (HANDLE)new_c->s, new_c->ov.hEvent, (ULONG_PTR)pc, 0 ); // pc is the global struct of proxy_client if (hrc == NULL) fprintf(stderr, "CompletionThread: CreateIoCompletionPort failed: %d\n", GetLastError()); int r = 0; if ( ( r = set_wsa_proxy_client ( new_c ) ) != 0 ) { // } else { // } This does not seem to trigger the socket when I GetQueuedCompletionStatus for ServerCompletionPort, after sending the socket data (from the server). I was wondering how I can set an IO for a socket! Thank for the help! :-)