Related
Here is the code I have for accept and recv
int sock = createSocket();
int rc = ::bind(sock, glDispenserServerConfig->m_szServerPort);
sockaddr_in clientAddr;
int clientAddrSize = sizeof(clientAddr);
int clientSock;
bool saveImage;
while (-1 != (clientSock = accept(sock,(sockaddr*)&clientAddr, (socklen_t*)&clientAddrSize))) {
string requestStr;
int bufSize = 5;
requestStr.resize(bufSize);
string data = "";
string::size_type position;
bool getFlag = false;
while(1) {
recv(clientSock, &requestStr[0], bufSize, 0);
data += requestStr;
// position = data.find("}");
if(requestStr[0] == '}')
break;
else if(requestStr[1] == '}')
break;
else if(requestStr[2] == '}')
break;
else if(requestStr[3] == '}')
break;
else if(requestStr[4] == '}')
break;
if(requestStr[0] == 'G' && requestStr[1] == 'E' && requestStr[2] == 'T' && requestStr[3] == ' ') {
getFlag = true;
for(int i = 0; i < 20; i++) {
recv(clientSock, &requestStr[0], bufSize, 0);
data += requestStr;
}
break;
}
}
And two function being used:
int createSocket() {
int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock == -1) {
printf("Create socket failed!\n");
}
return sock;
}
bool bind(int &sock, unsigned short port) {
if (sock <= 0) {
createSocket();
}
sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = htons(0);
if (::bind(sock, (sockaddr*)&addr, sizeof(addr)) != 0) {
printf("bind port %d failed!\n", port);
return false;
}
printf("bind port %d succeeded.\n", port);
listen(sock, 10);
return true;
}
I was trying to get data stream from POST request. Since the size of body is unknown, I made a loop to read the whole body. And this port is designed for getting POST request, so I break the loop and made a flag for later use.
My issue here is I check the ending symbol which is "}" here. I'm worried about sometime if missing the ending symbol the server will be blocked by recv function.
So I wonder if there is some way I can set recv max waiting time, like 2 seconds it did not read anything from buffer then break the loop and continuous?
Based on the comments from Remy Lebeau, here is my new code:
sockaddr_in clientAddr;
int32 clientAddrSize = sizeof(clientAddr);
int32 clientSock;
bool saveImage;
struct timeval timeout;
socklen_t len = sizeof(timeout);
timeout.tv_sec = 10;
timeout.tv_usec = 0;
while (-1 != (clientSock = accept(sock, (sockaddr*)&clientAddr, (socklen_t*)&clientAddrSize))) {
int err = setsockopt(clientSock, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout.tv_sec, sizeof(struct timeval));
This will stop blocking by recv in 10 seconds
I am making a simple client server application where the client sends an image file(.jpg) to the server. But, the client is not able to connect to the server. Please tell me where I am going wrong. This is what I have done.
Client:
WSADATA wsaData;
SOCKET m_socket;
SOCKET m_backup;
sockaddr_in con;
SOCKET AcceptSocket;
WComm::WComm()
{
// Initialize Winsock.
int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != NO_ERROR)
printf("Error at WSAStartup()\n");
// Create a socket.
m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (m_socket == INVALID_SOCKET) {
printf("Error at socket(): %ld\n", WSAGetLastError());
WSACleanup();
return;
}
m_backup = m_socket;
}
void WComm::connectServer(char *ip, int port)
{
// Connect to a server.
con.sin_family = AF_INET;
con.sin_addr.s_addr = inet_addr(ip);
con.sin_port = htons(port);
if (connect(m_socket, (SOCKADDR*)&con, sizeof(con)) == SOCKET_ERROR) {
printf("Failed to connect.\n");
WSACleanup();
return;
}
}
int WComm::sendData(char *sendbuf)
{
return send(m_socket, sendbuf, strlen(sendbuf), 0);
}
int WComm::recvData(char *recvbuf, int size)
{
int sz = recv(m_socket, recvbuf, size, 0);
recvbuf[sz] = '\0';
return sz;
}
void WComm::closeConnection()
{
closesocket(m_socket);
m_socket = m_backup;
}
void WComm::fileSend(char *fpath)
{
// Extract only filename from given path.
char filename[50];
int i = strlen(fpath);
for (; i>0; i--)if (fpath[i - 1] == '\\')break;
for (int j = 0; i <= (int)strlen(fpath); i++)filename[j++] = fpath[i];
////////////////////////////////////////
ifstream myFile(fpath, ios::in | ios::binary | ios::ate);
int size = (int)myFile.tellg();
myFile.close();
char filesize[10]; itoa(size, filesize, 10);
send(m_socket, filename, strlen(filename), 0);
char rec[32] = ""; recv(m_socket, rec, 32, 0);
send(m_socket, filesize, strlen(filesize), 0);
recv(m_socket, rec, 32, 0);
FILE *fr = fopen("C:\\Images\\abc.jpg", "rb");
while (size > 0)
{
char buffer[1030];
if (size >= 1024)
{
fread(buffer, 1024, 1, fr);
send(m_socket, buffer, 1024, 0);
recv(m_socket, rec, 32, 0);
}
else
{
fread(buffer, size, 1, fr);
buffer[size] = '\0';
send(m_socket, buffer, size, 0);
recv(m_socket, rec, 32, 0);
}
size -= 1024;
}
fclose(fr);
}
WComm w;
void main(int argc, char *argv[])
{
runclient(argv[1], argv[2]);
}
void runclient(char *ip, char *fpath)
{
char rec[32] = "";
// Connect To Server
w.connectServer(ip, 27015);
printf("Connected to server...\n");
// Sending File
w.sendData("FileSend");
w.recvData(rec, 32);
w.fileSend(fpath);
printf("File Sent.............\n");
// Send Close Connection Signal
w.sendData("EndConnection"); w.recvData(rec, 32);
printf("Connection ended......\n");
}
Server:
#include "wcomm.h"
WSADATA wsaData;
SOCKET m_socket;
SOCKET m_backup;
sockaddr_in con;
SOCKET AcceptSocket;
WComm::WComm()
{
// Initialize Winsock.
int iResult = WSAStartup( MAKEWORD(2,2), &wsaData );
if ( iResult != NO_ERROR )
printf("Error at WSAStartup()\n");
// Create a socket.
m_socket = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
if ( m_socket == INVALID_SOCKET ) {
printf( "Error at socket(): %ld\n", WSAGetLastError() );
WSACleanup();
return;
}
m_backup = m_socket;
}
void WComm::startServer(int port)
{
// Connect to a server.
con.sin_family = AF_INET;
con.sin_addr.s_addr = inet_addr( "0.0.0.0" );
con.sin_port = htons( port );
if ( bind( m_socket, (SOCKADDR*) &con, sizeof(con) ) == SOCKET_ERROR) {
printf( "Failed to connect.\n" );
WSACleanup();
return;
}
// Listen on the socket.
if ( listen( m_socket, 1 ) == SOCKET_ERROR )
printf( "Error listening on socket.\n");
}
void WComm::waitForClient()
{
AcceptSocket = SOCKET_ERROR;
while ( AcceptSocket == SOCKET_ERROR ) {
AcceptSocket = accept( m_backup, NULL, NULL );
}
m_socket = AcceptSocket;
}
int WComm::sendData(char *sendbuf)
{
return send( m_socket, sendbuf, strlen(sendbuf), 0 );
}
int WComm::recvData(char *recvbuf,int size)
{
int sz = recv( m_socket, recvbuf, size, 0 );
recvbuf[sz] = '\0';
return sz;
}
void WComm::closeConnection()
{
closesocket(m_socket);
m_socket = m_backup;
}
void WComm::fileReceive(char *filename)
{
char rec[50] = "";
recv( m_socket, filename, 32, 0 );
send( m_socket, "OK", strlen("OK"), 0 );
FILE *fw = fopen(filename, "wb");
int recs = recv( m_socket, rec, 32, 0 );
send( m_socket, "OK", strlen("OK"), 0 );
rec[recs]='\0';
int size = atoi(rec);
while(size > 0)
{
char buffer[1030];
if(size>=1024)
{
recv( m_socket, buffer, 1024, 0 );
send( m_socket, "OK", strlen("OK"), 0 );
fwrite(buffer, 1024, 1, fw);
}
else
{
recv( m_socket, buffer, size, 0 );
send( m_socket, "OK", strlen("OK"), 0 );
buffer[size]='\0';
fwrite(buffer, size, 1, fw);
}
size -= 1024;
}
fclose(fw);
}
WComm w;
void main(int argc, char *argv[])
{
runserver();
}
void runserver()
{
// Start Server Daemon
w.startServer(27015);
printf("Server Started........\n");
while (TRUE) {
// Wait until a client connects
w.waitForClient();
printf("Client Connected......\n");
// Work with client
while (TRUE)
{
char rec[50] = "";
w.recvData(rec, 32);
w.sendData("OK");
if (strcmp(rec, "FileSend") == 0)
{
char fname[32] = "";
w.fileReceive(fname);
printf("File Received.........\n");
}
if (strcmp(rec, "EndConnection") == 0)break;
printf("Connection Ended......\n");
}
// Disconnect client
w.closeConnection();
}
}
Also, if I want to send more than 1 image, then what should I do for that? Would going for Generic List be a good idea to hold all the images which I want to send? How to go for this? Please help
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.
I'm working on a c++ class that acts as a high-level wrapper around sockets in linux. While testing it, I purposely made the server's accept() call time out by having the client application sleep for a few seconds before calling connect().
However, after the server times out, the client application is still able to call connect() and send data without detecting an error. This is obviously a problem, because the server is not receiving the data, so the client should know the connection failed.
Here is my code. The server app calls Socket::accept_connection() and the client app sleeps and then calls Socket::connect_to().
// Accept a connection on the server side with a timeout
Socket *Socket::accept_connection(double timeout) {
Socket *new_connection = NULL;
socklen_t sin_size;
struct sockaddr_storage client_address; // Client's address
struct sockaddr_in client_port_address; // Client's port
char s[INET6_ADDRSTRLEN];
sin_size = sizeof client_address;
fd_set rfds;
struct timeval timeout_structure;
timeout_structure.tv_sec = (long)(timeout);
timeout_structure.tv_usec = int((timeout - timeout_structure.tv_sec) * 1e6);
struct timeval *timeout_ptr = NULL;
if(timeout > 0)
timeout_ptr = &timeout_structure;
// Loop until the timeout has been reached
while(true) {
FD_ZERO(&rfds);
FD_SET(socket_desc, &rfds);
if(select(socket_desc + 1, &rfds, NULL, NULL, timeout_ptr) > 0) {
int client_sock = accept(socket_desc, (struct sockaddr *)&client_address, &sin_size);
if(client_sock == -1) {
// Failed to connect
connected = false;
continue;
} else {
// Connected
inet_ntop(client_address.ss_family, get_in_addr((struct sockaddr *)&client_address), s, sizeof s);
getpeername(client_sock, (struct sockaddr*)&client_port_address, &sin_size);
int client_port = ntohs(client_port_address.sin_port);
// ...
}
} else {
// Timed out
connected = false;
std::cout << "accept() timed out\n";
break;
}
}
return new_connection;
}
// Connect to the given ip address and port
bool Socket::connect_to(std::string server_ip, int server_port, double timeout) {
connected = false;
// Create the socket and allocate memory for reading in data
struct addrinfo hints, *servinfo, *p;
int rv;
char s[INET6_ADDRSTRLEN];
struct timeval timeout_structure;
timeout_structure.tv_sec = (long)(timeout);
timeout_structure.tv_usec = int((timeout - timeout_structure.tv_sec) * 1e6);
struct timeval *timeout_ptr = NULL;
if(timeout > 0)
timeout_ptr = &timeout_structure;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
if ((rv = getaddrinfo(server_ip.c_str(), std::to_string(server_port).c_str(), &hints, &servinfo)) != 0) {
fprintf(stderr, "Socket error: connect_to, getaddrinfo: %s\n", gai_strerror(rv));
throw;
}
// loop through all the results and connect to the first we can
for(p = servinfo; p != NULL; p = p->ai_next) {
if ((socket_desc = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) {
perror("Socket error: connect_to, socket");
continue;
}
int flags = 0, error = 0, ret = 0;
fd_set rset, wset;
socklen_t len = sizeof(error);
//clear out descriptor sets for select
//add socket to the descriptor sets
FD_ZERO(&rset);
FD_SET(socket_desc, &rset);
wset = rset; //structure assignment ok
//set socket nonblocking flag
if((flags = fcntl(socket_desc, F_GETFL, 0)) < 0)
continue;
if(fcntl(socket_desc, F_SETFL, flags | O_NONBLOCK) < 0)
continue;
//initiate non-blocking connect
if(ret = connect(socket_desc, p->ai_addr, p->ai_addrlen) == -1) {
if (errno != EINPROGRESS) {
close(socket_desc);
perror("Socket error: connect_to, could not connect");
continue;
}
}
if(ret != 0) { // If connect did not succeed right away
// We are waiting for connect to complete now
if((ret = select(socket_desc + 1, NULL, &wset, NULL, timeout_ptr)) < 0)
return false;
if(ret == 0){ //we had a timeout
errno = ETIMEDOUT;
return false;
}
//we had a positive return so a descriptor is ready
if(FD_ISSET(socket_desc, &rset) || FD_ISSET(socket_desc, &wset)){
if(getsockopt(socket_desc, SOL_SOCKET, SO_ERROR, &error, &len) < 0 || error != 0)
return false;
} else
return false;
if(error){ //check if we had a socket error
errno = error;
return false;
}
}
//put socket back in blocking mode
if(fcntl(socket_desc, F_SETFL, flags) < 0)
return false;
break;
}
if(p == NULL) {
fprintf(stderr, "Socket error: connect_to, failed to connect\n");
socket_desc = 0;
return false;
}
inet_ntop(p->ai_family, get_in_addr((struct sockaddr *)p->ai_addr), s, sizeof s);
freeaddrinfo(servinfo); // all done with this structure
connected = true;
return connected;
}
This is normal, not a problem.
TCP maintains a listen backlog queue into which connections are placed that have been completed by the TCP stack but not yet accepted by the application.
TCP maintains a socket receive buffer per socket into which data is placed that has arrived from the peer and not yet been read by the application.
the client should know the connection failed.
It didn't fail. The server can accept it and read the data.
I've just created client - server communication via multithreading.
My problem is that I want to display a message after every 20 seconds when no message has been received.
Here's my code:
int main(int argc , char *argv[])
{
int socket_desc , new_socket , c;
struct sockaddr_in server , address;
socket_desc = socket(AF_INET , SOCK_STREAM , 0);
if (socket_desc == -1)
{
perror("socket failed");
exit(EXIT_FAILURE);
}
struct timeval timeout;
timeout.tv_sec = 3;
timeout.tv_usec = 0;
// if (setsockopt (socket_desc, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout)) < 0)
// perror("setsockopt failed\n");
// if (setsockopt (socket_desc, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(timeout)) < 0)
// perror("setsockopt failed\n");
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons( PORT );
if( bind(socket_desc,(struct sockaddr *)&server , sizeof(server)) < 0)
{
perror("bind failed");
exit(EXIT_FAILURE);
}
listen(socket_desc , 3);
puts("Oczekiwanie na połączenia ...");
c = sizeof(struct sockaddr_in);
pthread_t thread_id;
while( (new_socket = accept(socket_desc, (struct sockaddr *)&address, (socklen_t*)&c)) )
{
printf("Połączono z nowym klientem, socket fd: %d , ip: %s , port: %d \n" , new_socket , inet_ntoa(address.sin_addr) , ntohs(address.sin_port));
if( pthread_create( &thread_id , NULL , connection_handler , (void*) &new_socket) < 0)
{
perror("ERROR: nie można utworzyć wątku");
exit(EXIT_FAILURE);
}
}
if (new_socket < 0)
{
perror("accept failed");
exit(EXIT_FAILURE);
}
return 0;
}
and handler function:
void *connection_handler(void *socket_desc)
{
int sock = *(int*)socket_desc;
int read_size;
char *message , client_message[2000];
message = "Nazwiązano połączenie z serwerem \r\n";
write(sock , message , strlen(message));
//przetwarzanie wiadomosci
while( (read_size = recv(sock , client_message , 2000 , 0)) > 0 )
{
client_message[read_size] = '\0';
printf("%s", client_message);
memset(client_message, 0, 2000);
}
if(read_size == 0)
{
printf("Połączenie z klientem zostało przerwane\n");
fflush(stdout);
}
else if(read_size == -1)
{
perror("recv failed");
}
return 0;
}
I would like get the same result as Select here:
struct timeval tv;
tv.tv_sec = 20;
tv.tv_usec = 0;
activity = select( max_sd + 1 , &readfds , NULL , NULL , &tv);
if (activity == -1)
perror("select() failed");
else if (activity){
tv.tv_sec = delay;
}
else{
time_t t = time(0);
cout << "DELAY MESSAGE: " << currentDateTime() << endl;
tv.tv_sec += delay;
}
Any suggestions? Thanks a lot for any help!
You need to set socket option to SO_RCVTIMEO. Refer the following link for more info on this socket option.
http://linux.die.net/man/3/setsockopt
your code in connection_handler should set this option as below
struct timeval tv;
tv.tv_sec = 20; /* 20 Secs Timeout */
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO,(struct timeval *)&tv,sizeof(struct timeval));
/*Now you should read*/
Your read method would unblock after specified time of 20 seconds with errno set to EAGAIN EWOULDBLOCK. You could handle this errno in the loop condition to get the desired functionality.