winsock吧 关注:23贴子:76
  • 0回复贴,共1

winsock2 服务器端recv返回0?找不出原因

只看楼主收藏回复

建立了服务器端和客户端的socket,客户端成功连接上服务器端,但是向服务器端发送数据的时候,服务器端的recv返回结果直接为0,导致直接退出服务器和客户端的连接线程,提示“#################与客户端XXX连接中断!############”始终找不出原因,感谢大家解答!
服务器端代码:
<coding-1 lang="as">
#include <ws2tcpip.h>
#include <WinSock2.h>
#include <string>
#include <iostream>
#include <fstream>
#pragma comment(lib,"ws2_32.lib")
using namespace std;
#define MAX_SEND_LEN 100
#define MAX_RESPONSE_LEN 100
#define MAX_CONNECT_COUNT 50
#define DEFAULT_PORT "19933"
DWORD WINAPI myConnectThread(LPVOID lpParam);
HANDLE wait_can_connect_event;
int threadCount = 0;
inline void log(char *con){
ofstream outfile;
outfile.open("log.txt",ios::app);
outfile<<con<<endl;
outfile.clear();
outfile.close();
}
inline void getHostIp()
{
char hostname[128];
gethostname(hostname, 128);
hostent* hostip = gethostbyname(hostname);
log("hostip:");
char **pptr;
char str[32];
pptr = hostip->h_addr_list;
for (; *pptr != NULL; pptr++) {
inet_ntop(hostip->h_addrtype, *pptr, str, sizeof(str));
printf("address: %s\n", str);
log(str);
}
}
//判断字符串中是否含有汉子。返回0:无中文,返回1:有中文
inline int IncludeChinese(char *str)
{
char c;
while(1)
{
c=*str++;
if (c==0) break; //如果到字符串尾则说明该字符串没有中文字符
if (c&0x80) //如果字符高位为1且下一字符高位也是1则有中文字符
if (*str & 0x80) return 1;
}
return 0;
}
typedef struct MyData{
SOCKET clientSocket; //客户端连接实例
SOCKADDR_IN clientAddr; //客户端的地址信息
} MYDATA, *PMYDATA;
SOCKET ListenSocket = INVALID_SOCKET;
SOCKET ClientSocket = INVALID_SOCKET;
//char mySendData[MAX_SEND_LEN];
//char myRecvData[MAX_SEND_LEN];
HANDLE myThreadArray[MAX_CONNECT_COUNT];
int main(int argc, char **argv){
//getHostIp();
wait_can_connect_event = CreateEvent(NULL,TRUE,FALSE,NULL);
WSADATA wsaData;
struct addrinfo *result = NULL;
struct addrinfo hints;
string ip_canuse;
if(WSAStartup(MAKEWORD(2,2), &wsaData) != 0){
printf("socket启动失败:%d\n",WSAGetLastError());
return -1;
}
memset(&hints,0,sizeof(hints));
hints.ai_family = AF_UNSPEC; //协议无关,适用于ipv4和ipv6
hints.ai_socktype = SOCK_STREAM; //返回仅仅是流套接口的信息
hints.ai_protocol = IPPROTO_TCP; //TCP协议
hints.ai_flags = AI_PASSIVE; //被动地,用于bind
WSAStartup(MAKEWORD(2, 2), &wsaData);
char Name[32] = { 0 };
if (!gethostname(Name, 32))
{
hostent *hostinfo;
if (hostinfo = gethostbyname(Name))
{
ip_canuse = inet_ntoa(*(struct in_addr *)*hostinfo->h_addr_list);
}
}
log("可用的IP地址:");
log((char *)ip_canuse.c_str());
//***********************华丽分割线(建立Socket并连接服务器)**********************************
string myPort = DEFAULT_PORT; //监听的端口
int reGetCount = 0;
while(getaddrinfo(ip_canuse.c_str(), myPort.c_str(), &hints, &result) != 0){
printf("端口%s解析失败,切换端口中...\n",myPort);
char t[256];
sprintf(t, "%d", rand()%60000 + 1024);
myPort = t;
if(reGetCount++>6){
WSACleanup();
return -1;
}
}
struct addrinfo *ptr = result;
int bindRes;
while(ptr != NULL){
//创建TCP连接套接字
ListenSocket = socket(ptr->ai_family, ptr->ai_socktype,ptr->ai_protocol);
if (ListenSocket == INVALID_SOCKET) {
printf("创建套接字失败: %d\n", WSAGetLastError());
WSACleanup();
freeaddrinfo(result);
return -1;
}
//创建TCP监听套接字
bindRes = bind(ListenSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
if(bindRes != SOCKET_ERROR)
break;
closesocket(ListenSocket);
ListenSocket = INVALID_SOCKET;
ptr = ptr->ai_next;
}
if(ListenSocket == INVALID_SOCKET){
printf("套接字端口绑定失败: %d\n", WSAGetLastError());
WSACleanup();
return -1;
}
freeaddrinfo(result);
if(listen(ListenSocket, SOMAXCONN) == SOCKET_ERROR){
printf("套接字监听失败: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return -1;
}
printf("服务器开启成功,开启地址%s,监听端口%d\n", ip_canuse.c_str(), atoi(myPort.c_str()));
//**********************华丽分割线(接受客户端连接,并分别开启线程处理)*********************
SOCKADDR_IN clinetAddr;
//int addrSize = sizeof(clinetAddr);
int addrSize = 65535;
do{
if(threadCount>=MAX_CONNECT_COUNT){
printf("连接已达上限");
ResetEvent(wait_can_connect_event);
if(WaitForSingleObject(wait_can_connect_event,INFINITE) == WAIT_OBJECT_0) //如果可以新的连接
continue;
}
printf("当前连接数:%d,等待新的客户端连接..........\n",threadCount);
ClientSocket = accept(ListenSocket, (sockaddr*)&clinetAddr, &addrSize);
if (ClientSocket == INVALID_SOCKET) {
printf("接受客户端的连接失败: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
break;
}
//===============开启客户端服务器端连接线程==================
PMYDATA _data;
_data = (PMYDATA) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,sizeof(MYDATA));
_data->clientSocket = ClientSocket;
_data->clientAddr = clinetAddr;
myThreadArray[threadCount] = CreateThread(NULL,0,myConnectThread,_data,0,NULL);
if(myThreadArray[threadCount] == NULL)
{
printf("创建客户端连接线程失败...");
continue;
}
if(_data==NULL)
{
CloseHandle(myThreadArray[threadCount]);
printf("创建客户端连接线程失败......");
}
threadCount++;
}while(true);
closesocket(ListenSocket);
system("pause");
return 0;
}
DWORD WINAPI myConnectThread( LPVOID lpParam )
{
PMYDATA socketData = (PMYDATA)lpParam;
SOCKET _clientSocket = socketData->clientSocket;
USHORT portNum = socketData->clientAddr.sin_port;
int curThreadPos = threadCount;
printf("==========连接%d:成功与客户端%s端口%d建立连接==========\n",curThreadPos,inet_ntoa(socketData->clientAddr.sin_addr),portNum);
int recvResult = -1;
char myRecvData[MAX_SEND_LEN] = {'\0'};
char mySendData[MAX_SEND_LEN] = {'\0'};
int re_recv_count = 0; //重新接收次数...
int sendDataLength = 0;
string resBody;
while(recvResult=recv(_clientSocket, myRecvData, (int)strlen(myRecvData), 0)&&re_recv_count<=5){
if(myRecvData[0] == '\0' || strlen(myRecvData)==0){
printf("接收到的数据是空的\n");
continue;
}
if(recvResult>0){ //接收到了客户端发来的数据
printf("【客户%d】:%s(%d字节)\n",curThreadPos,myRecvData,recvResult);
re_recv_count = 0;
if(IncludeChinese(myRecvData)==1){ //接收到的字符串中含中文
printf("连接%d:>>>>>>>>>>>>请输入回复内容:",curThreadPos);
cin.clear();// 重置 cin 输入状态
cin.sync();// 清除 cin 缓冲区未读取信息
getline(cin, resBody);
strcpy(mySendData,resBody.c_str());
}else{ //不含中文直接返回原英文
memcpy(mySendData,myRecvData,sizeof(myRecvData));
}
sendDataLength = send(_clientSocket, mySendData, (int)strlen(mySendData), 0);
printf("【我】:%s (%d字节)\n",mySendData,sendDataLength);
}else if(recvResult == 0){ //客户端和服务器端断开连接
break;
}else{
log("失败++");
printf("连接%d:>>>>>>>>>>>>>>>>>>接收客户端数据失败:%d,第%d次重试...\n", curThreadPos,WSAGetLastError(),++re_recv_count);
}
ZeroMemory(mySendData, MAX_SEND_LEN);
ZeroMemory(myRecvData, MAX_SEND_LEN);
/*memset(mySendData,'\0',MAX_SEND_LEN);
memset(myRecvData,'\0',MAX_SEND_LEN);*/
resBody.clear();
}
shutdown(_clientSocket, SD_SEND);
closesocket(_clientSocket);
printf("#################与客户端%s连接中断!############\n", inet_ntoa(socketData->clientAddr.sin_addr),portNum);
CloseHandle(myThreadArray[curThreadPos-1]);
myThreadArray[curThreadPos - 1] = NULL;
threadCount--;
if(threadCount<=MAX_CONNECT_COUNT-1)
SetEvent(wait_can_connect_event);//开启连接建立
return 0;
}
</coding>
客户端代码
<coding-3 lang="cpp">
#include <ws2tcpip.h>
#include <WinSock2.h>
#include <string>
#include <iostream>
#include <fstream>
#pragma comment(lib, "ws2_32.lib")
using namespace std;
#define MAX_SEND_LEN 100
#define MAX_TIMEOUT 10*1000
DWORD WINAPI myRecvThread( LPVOID lpParam );
inline void log(char *con){
ofstream outfile;
outfile.open("log.txt",ios::app);
outfile<<con<<endl;
outfile.clear();
outfile.close();
}
bool waitForRes = false;
HANDLE finish_send_data_event,finish_recv_thread_event,can_send_event;
HANDLE recv_thread;
SOCKET myConnectSocket = INVALID_SOCKET;
char mySendData[MAX_SEND_LEN];
char myRecvData[MAX_SEND_LEN];
string myIpAddr;
string myPort;
int main(int argc, char **argv){
finish_send_data_event = CreateEvent(NULL,TRUE,FALSE,NULL);
finish_recv_thread_event = CreateEvent(NULL,TRUE,FALSE,NULL);
can_send_event = CreateEvent(NULL,TRUE,TRUE,NULL);
WSADATA wsaData;
int resCode;
string exitKey;
struct addrinfo *result = NULL;
struct addrinfo hints;
if(WSAStartup(MAKEWORD(2,2), &wsaData) != 0){
printf("socket启动失败:%d\n",WSAGetLastError());
return -1;
}
if(argc==3){
myIpAddr = (string)argv[1];
myPort = (string)argv[2];
}
while(argc != 3 && (myIpAddr.empty() || myIpAddr == "")){
printf("请输入服务器IP地址:");
cin >> myIpAddr;
if(myIpAddr.empty() || myIpAddr == "")
continue;
while(myPort.empty() || atoi(myPort.c_str())==0){
printf("请输入服务器对应的端口号:");
cin >> myPort;
}
}
memset(&hints,0,sizeof(hints));
hints.ai_family = AF_UNSPEC; //协议无关,适用于ipv4和ipv6
hints.ai_socktype = SOCK_STREAM; //返回仅仅是流套接口的信息
hints.ai_protocol = IPPROTO_TCP; //TCP协议
//***********************华丽分割线(建立Socket并连接服务器)**********************************
//getaddrinfo函数能够处理名字到地址以及服务到端口这两种转换
if(getaddrinfo(myIpAddr.c_str(), myPort.c_str(), &hints, &result) != 0){
printf("地址信息解析失败!\n");
WSACleanup();
return -1;
}
struct addrinfo *ptr = result;
while(ptr != NULL){
//创建连接服务器套接字
myConnectSocket = socket(ptr->ai_family, ptr->ai_socktype,ptr->ai_protocol);
if (myConnectSocket == INVALID_SOCKET) {
printf("创建连接服务器套接字失败: %d\n", WSAGetLastError());
WSACleanup();
freeaddrinfo(result);
return -1;
}
//和服务器建立连接
if (connect(myConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen) != SOCKET_ERROR)
break;
//log("连接失败喽!!");
printf("连接失败喽!!%d\n", WSAGetLastError());
closesocket(myConnectSocket);
myConnectSocket = INVALID_SOCKET;
ptr = ptr->ai_next;
}
freeaddrinfo(result);
if(myConnectSocket == INVALID_SOCKET){
printf("和服务器连接失败: %d\n", WSAGetLastError());
WSACleanup();
log("和服务器连接失败...");
system("pause");
return -1;
}
printf("**************与服务器%s成功建立了套接字连接!*************\n",myIpAddr.c_str());
//***********************华丽分割线(建立接收数据线程)***************************
recv_thread = CreateThread(NULL,0,myRecvThread,NULL,0,NULL);
//***********************华丽分割线(发送数据)***********************************
int sendDataLength = 0;
while(WaitForSingleObject(finish_send_data_event, 0) != WAIT_OBJECT_0){
printf("请输入要发送的数据(最大65535字节):");
cin >> mySendData;
log(mySendData);
if(strcmp(mySendData,"exit")==0){
printf("您输入了中断连接指令,即将与主机%s中断连接...\n",myIpAddr.c_str());
Sleep(2000);
SetEvent(finish_recv_thread_event);
break;
}
if(mySendData[0] == '\0' || strlen(mySendData) == 0) continue;
sendDataLength = send(myConnectSocket, mySendData, (int)strlen(mySendData), 0);
if (sendDataLength == SOCKET_ERROR) {
printf("发送数据失败: %d\n", WSAGetLastError());
break;
}
printf("【我】: %s(%d字节)\n", mySendData,sendDataLength);
waitForRes = true;
memset(mySendData,'\0',MAX_SEND_LEN);
ResetEvent(can_send_event);
if(WaitForSingleObject(can_send_event,MAX_TIMEOUT)==WAIT_TIMEOUT){ //每次发完停在这,等候1分钟之内接收到回复
printf(">>>>>>>>>>>>>>>>>与主机%s对话超时......<<<<<<<<<<<<<<<<<<<<<<<\n", myIpAddr.c_str());
break;
}
}
if(recv_thread != NULL){
CloseHandle(recv_thread);
}
shutdown(myConnectSocket, SD_SEND);
closesocket(myConnectSocket);
WSACleanup();
printf("#################与服务器%s连接中断!############\n",myIpAddr.c_str());
system("pause");
return 0;
}
DWORD WINAPI myRecvThread( LPVOID lpParam )
{
int iResult = -1;
while(WaitForSingleObject(finish_recv_thread_event,0) != WAIT_OBJECT_0){
iResult = recv(myConnectSocket, myRecvData, (int)strlen(myRecvData), 0);
if (iResult > 0){
printf("【服务器】:%s (%d字节)\n",myRecvData,iResult);
memset(myRecvData,'\0',MAX_SEND_LEN);
waitForRes = false;
SetEvent(can_send_event);
continue;
}
if(!waitForRes) continue;
if (iResult == 0){
printf("和服务器的连接已关闭\n");
SetEvent(can_send_event);
SetEvent(finish_send_data_event);
break;
}
printf("接收数据失败: %d\n", WSAGetLastError());
//waitForRes = false;
}
return 0;
}
</coding>


1楼2015-11-21 14:37回复