Всем доброго дня!
Проблема моя связанная с тем, что когда сервер отправляет клиенту сообщение через send(), клиент через select() определяет что пора вызвать recv() и этот самый recv() возвращает 0, то есть сервер разорвал соединение с клиентом. Но я ведь не разрывал, а просто прислал сообщение. Почему так? Сам уже два дня не могу понять причину. Помогите! Ниже всё подробно...
Есть сервер, со следующим алгоритмом работы:
1. WSAStartup()
2. socket()
3. bind()
4. listen()
5. accept()
6. send()
7. recv()
8. goto 7
Сервер работает нормально. Если что, вот полный код:
#pragma comment(lib,"ws2_32.lib")
#include <iostream>
#include <WinSock2.h>
using namespace std;
SOCKET listener=0;
SOCKET client=0;
void release(void);
int main(void)
{
WSADATA sockData;
cout<<"Init... ";
if(WSAStartup(MAKEWORD(2,2),&sockData))
{
cout<<"[ERROR]"<<endl;
release();
return -1;
}
cout<<"[OK]"<<endl;
cout<<"Socket... ";
listener=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(listener==INVALID_SOCKET)
{
cout<<"[ERROR]"<<endl;
release();
return -1;
}
sockaddr_in sockAddr;
memset(&sockAddr,0,sizeof(sockaddr_in));
sockAddr.sin_family = AF_INET;
sockAddr.sin_addr.S_un.S_addr = ADDR_ANY;
sockAddr.sin_port = 30002;
cout<<"[OK]"<<endl;
cout<<"Bind... ";
if(bind(listener,(const sockaddr*)&sockAddr,sizeof(sockaddr_in))==SOCKET_ERROR)
{
cout<<"[ERROR]"<<endl;
release();
return -1;
}
cout<<"[OK]"<<endl;
cout<<"Listen... ";
if(listen(listener,20)==SOCKET_ERROR)
{
cout<<"[ERROR]"<<endl;
release();
return -1;
}
int size=sizeof(sockaddr_in);
cout<<"[OK]"<<endl;
cout<<"Accept... ";
client=accept(listener,(sockaddr*)&sockAddr,&size);
if(client==INVALID_SOCKET)
{
cout<<"[ERROR]"<<endl;
release();
return -1;
}
cout<<"[OK]"<<endl;
char buf[256];
memset(buf,0,256);
buf[0]='S';
buf[1]='e';
buf[2]='r';
buf[3]='g';
buf[4]='e';
buf[5]='i';
int res=0;
cout<<"Send... ";
int index=0;
while(index!=6)
{
int snd=send(client,buf+index,6-index,0);
if(snd==SOCKET_ERROR)
{
cout<<"[ERROR]"<<endl;
release();
return -1;
}
index+=snd;
}
cout<<"[OK]"<<endl;
bool isExit=false;
while(!isExit)
{
cout<<"Wait... ";
res=recv(client,buf,256,0);
if(res==0)
{
cout<<"[DISCONNECT]"<<endl;
isExit=true;
}
else if(res==SOCKET_ERROR)
{
if(WSAGetLastError()==WSAECONNRESET)
cout<<"[DISCONNECT]"<<endl;
else
cout<<"[ERROR]"<<endl;
isExit=true;
}
else
{
cout<<"[MESSAGE]"<<endl;
}
}
release();
return 0;
}
void release(void)
{
if(listener) closesocket(listener);
if(client) closesocket(client);
WSACleanup();
system("pause");
}
Есть клиент, алгоритм работы которого следующий:
1. WSAStartup()
2. socket()
3. bind()
4. connect()
А в отдельном потоке (проверку на разрешение записи я не делаю):
1. select()
2. recv()
Если более подробно, то так происходит создание клиента:
result client_base::init(const string& _local_ip,port _local_port,const string& _remote_ip,port _remote_port,event_type _type,client_event* _event,time _wait_time,size _length)
{
if(!_remote_ip.length()) return error_parameter;
if(!_event) return error_pointer;
if(!_length) return error_parameter;
eventType=_type;
eObject=_event;
waitTime=_wait_time;
sClient=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(sClient==INVALID_SOCKET)
{
sClient=0;
return error_socket;
}
sockaddr_in sockAddr;
memset(&sockAddr,0,sizeof(sockaddr_in));
sockAddr.sin_family = AF_INET;
sockAddr.sin_port = _local_port;
char* buf=0;
if(_local_ip.length())
{
buf=new (std::nothrow) char[_local_ip.length()+1];
if(!buf) return error_memory;
memset(buf,0,_local_ip.length()+1);
if(!WideCharToMultiByte(CP_ACP,0,_local_ip(),_local_ip.length(),buf,_local_ip.length(),0,0))
{
delete[] buf;
return error_os;
}
sockAddr.sin_addr.S_un.S_addr=inet_addr(buf);
delete[] buf;
}
if(bind(sClient,(const sockaddr*)&sockAddr,sizeof(sockaddr_in))==SOCKET_ERROR) return error_socket;
memset(&sockAddr,0,sizeof(sockaddr_in));
sockAddr.sin_family = AF_INET;
sockAddr.sin_port=_remote_port;
buf=new (std::nothrow) char[_remote_ip.length()+1];
if(!buf) return error_memory;
memset(buf,0,_remote_ip.length()+1);
if(!WideCharToMultiByte(CP_ACP,0,_remote_ip(),_remote_ip.length(),buf,_remote_ip.length(),0,0))
{
delete[] buf;
return error_os;
}
sockAddr.sin_addr.S_un.S_addr=inet_addr(buf);
delete[] buf;
if(connect(sClient,(const sockaddr*)&sockAddr,sizeof(sockaddr_in))==SOCKET_ERROR) return error_socket;
hThread=CreateThread(0,0,winThread,this,0,&hThreadID);
if(!hThread)
{
closesocket(sClient);
sClient=0;
return error_os;
}
return ok;
}
При этом функция потока:
DWORD WINAPI client_base::winThread(void* _param)
{
return ((client_base*)_param)->thread();
}
В свою очередь:
DWORD client_base::thread(void)
{
int sel=0;
FD_SET fdsRead;
timeval time;
client_base* ins=0;
FD_ZERO(&fdsRead);
if(eventType==event_receive || eventType==event_both) FD_SET(sClient,&fdsRead);
time.tv_sec=0;
time.tv_usec=(long)waitTime*1000;
eObject->dns_client_connect();
if(bClose)
{
eObject->dns_client_close(close_client);
EnterCriticalSection(&csRelease);
ins=instance;
instance=0;
LeaveCriticalSection(&csRelease);
if(ins) delete ins;
return ok;
}
while(true)
{
if(waitTime)
sel=select(0,&fdsRead,0,0,&time);
else
sel=select(0,&fdsRead,0,0,0);
switch(sel)
{
case 0:
eObject->dns_client_close(close_time);
EnterCriticalSection(&csRelease);
ins=instance;
instance=0;
LeaveCriticalSection(&csRelease);
if(ins) delete ins;
return ok;
case SOCKET_ERROR:
switch(WSAGetLastError())
{
case WSAENOTSOCK:
switch(error)
{
case cet_ok:
break;
case cet_netdown:
case cet_reset:
eObject->dns_client_close(close_error);
break;
case cet_client:
eObject->dns_client_close(close_client);
break;
case cet_server:
eObject->dns_client_close(close_server);
break;
default:
eObject->dns_client_close(close_error);
break;
}
EnterCriticalSection(&csRelease);
ins=instance;
instance=0;
LeaveCriticalSection(&csRelease);
if(ins) delete ins;
return ok;
default:
eObject->dns_client_close(close_error);
break;
}
EnterCriticalSection(&csRelease);
ins=instance;
instance=0;
LeaveCriticalSection(&csRelease);
if(ins) delete ins;
return error_socket;
default:
break;
}
if(FD_ISSET(sClient,&fdsRead))
{
binary bin;
cet err;
result res;
res=read(bin,&err);
switch(res)
{
case ok:
switch(err)
{
case cet_ok:
eObject->dns_client_receive(bin);
if(bClose)
{
EnterCriticalSection(&csRelease);
ins=instance;
instance=0;
LeaveCriticalSection(&csRelease);
if(ins) delete ins;
return ok;
}
break;
case cet_client:
eObject->dns_client_close(close_client);
EnterCriticalSection(&csRelease);
ins=instance;
instance=0;
LeaveCriticalSection(&csRelease);
if(ins) delete ins;
return ok;
case cet_server:
eObject->dns_client_close(close_server);
EnterCriticalSection(&csRelease);
ins=instance;
instance=0;
LeaveCriticalSection(&csRelease);
if(ins) delete ins;
return ok;
default:
eObject->dns_client_close(close_error);
EnterCriticalSection(&csRelease);
ins=instance;
instance=0;
LeaveCriticalSection(&csRelease);
if(ins) delete ins;
return ok;
}
break;
case error_memory:
eObject->dns_client_close(close_error);
EnterCriticalSection(&csRelease);
ins=instance;
instance=0;
LeaveCriticalSection(&csRelease);
if(ins) delete ins;
return error_memory;
default:
eObject->dns_client_close(close_error);
EnterCriticalSection(&csRelease);
ins=instance;
instance=0;
LeaveCriticalSection(&csRelease);
if(ins) delete ins;
return error_socket;
}
}
}
EnterCriticalSection(&csRelease);
ins=instance;
instance=0;
LeaveCriticalSection(&csRelease);
if(ins) delete ins;
return ok;
}
И сама функция считывания:
result client_base::read(binary& _binary,cet* _error)
{
int res=0;
byte* buf=new (std::nothrow) byte[recvLength];
if(!buf)
{
*_error=cet_other;
return error_memory;
}
memset(buf,0,recvLength);
res=recv(sClient,(char*)buf,recvLength,0);
switch(res)
{
case 0:
*_error=cet_server;
closesocket(sClient);
sClient=0;
delete[] buf;
return ok;
case SOCKET_ERROR:
switch(WSAGetLastError())
{
case WSAENETDOWN:
*_error=cet_netdown;
closesocket(sClient);
sClient=0;
delete[] buf;
return error_socket;
case WSAENOTCONN:
case WSAENOTSOCK:
*_error=cet_client;
closesocket(sClient);
sClient=0;
delete[] buf;
return ok;
case WSAENETRESET:
case WSAECONNABORTED:
case WSAETIMEDOUT:
*_error=cet_reset;
closesocket(sClient);
sClient=0;
delete[] buf;
return error_socket;
case WSAECONNRESET:
*_error=cet_server;
closesocket(sClient);
sClient=0;
delete[] buf;
return ok;
default:
*_error=cet_other;
closesocket(sClient);
sClient=0;
delete[] buf;
return error_socket;
}
break;
}
if(!_binary.assign(buf,res))
{
*_error=cet_other;
delete[] buf;
return error_memory;
}
*_error=cet_ok;
delete[] buf;
return ok;
}