tcp通讯问题:循环连接一百多个ip,有时连不上

疯魔症 2010-02-05 09:08:14
情况是这样的,大概一百多台设备,服务器每隔30秒循环这一百多个ip,通过tcp协议从每台设备抓取数据,然后转发给本机的另一个端口,
每循环一次时给这个ip建立一个tcp连接,发送一条指令,读一次数据。
测试的时候用网线和设备直连的,而且是一台,连接发指令读数据都没有问题,现在到客户那里只安装4台就出问题了,tcp连接时很不稳定,
循环时有的ip连不上报10035的错误,ping是可以ping通的,用tcp测试工具单独连接发指令,都没问题。

综合的因素如下:整个服务器通讯程序比较大,线程有5个,有iocp模型,每个线程都有while(true)的这种死循环。
设备上的通讯板是单片机实现的,并且不是很成熟的板子,之前通讯一直有问题。
客户那里是大型的局域网,网关路由了什么的很多。不知道这几个情况影响大不大。

下面贴抓取数据部分代码。

void CatchUpsData()
{
if (_beginthread(CatchUpsData22, 0,NULL) == NULL)
{
printf("主动取数据线程开启失败!\n");
}
else
{
printf("主动取数据线程开启成功!\n");
}
}

SOCKET m_CatchSocket;
sockaddr_in m_OctopusAddr;

void CatchUpsData22(void * t)
{
Sleep(10 * 1000);


WSADATA wsaData;

if (WSAStartup(0x0202, &wsaData) != 0)//WSAStartup 调用Socket前必须指定版本
{
printf("WSAStartup failed with error\n" );
return ;
}

// Create a listening socket
if ((m_CatchSocket = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, //流的方式创建Sock
WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET)
{
printf("WSASocket() failed with error %d\n", WSAGetLastError());
return ;
}

char host_name[255];
//获取本地主机名称
if (gethostname(host_name, sizeof(host_name)) == SOCKET_ERROR)
{
printf("Error %d when getting local host name.n", WSAGetLastError());
return ;
}

struct hostent *phe = gethostbyname(host_name);

struct in_addr addr;

memcpy(&addr, phe->h_addr_list[0], sizeof(struct in_addr));

m_OctopusAddr.sin_family = AF_INET;
m_OctopusAddr.sin_addr.s_addr = inet_addr(inet_ntoa(addr));
m_OctopusAddr.sin_port = htons(6018);

if(connect(m_CatchSocket,(sockaddr *)&m_OctopusAddr,sizeof(m_OctopusAddr)) == -1)
{
printf("本地连接Socket失败!%d\n",WSAGetLastError());
return ;
}
else
{
CatchUpsMake(true); //开始死循环,取数据
}

//关闭连接
if (closesocket(m_CatchSocket) == SOCKET_ERROR)
{
printf("closesocket() failed with error %d\n", WSAGetLastError());
}
}


// 取出SOCKET连接客户端的ip地址
CHAR * GetIP(SOCKET s)
{
struct sockaddr_in name;
int namelen = sizeof(struct sockaddr_in);
if(0 != getpeername(s, (sockaddr *)&name, &namelen))
{
printf("Get client address from SOCKET failed\n");
return NULL;
}
else
{
// 得到地址字符串
return inet_ntoa(name.sin_addr);
}
}

void CatchUpsMake(bool bFlag)
{
char DataBuff[1024]; //缓存
memset(DataBuff,'\0',1024);

printf("开始循环读取数据!\n");

while(bFlag)
{
//计时
SYSTEMTIME OldTime;
GetLocalTime(&OldTime);

TCHAR * config_dir = getAppConfigDir();//每30秒循环时,读一次config.ini文件
int iTimeOutConn = GetPrivateProfileInt(L"Time Out",L"TimeOutConn",100,config_dir);
int iTimeOutSend = GetPrivateProfileInt(L"Time Out",L"TimeOutSend",100,config_dir);
int iTimeOutRecv = GetPrivateProfileInt(L"Time Out",L"TimeOutRecv",100,config_dir);

if(0 == iTimeOutConn)
{
printf("读取连接超时失败,将使用默认超时!\n");
iTimeOutConn = 300;
}

if(0 == iTimeOutSend)
{
printf("读取发送超时失败,将使用默认超时!\n");
iTimeOutSend = 100;
}

if(0 == iTimeOutRecv)
{
printf("读取接收超时失败,将使用默认超时!\n");
iTimeOutRecv = 100;
}

printf("\n");
for (DWORD index=0; index<g_connections.size(); index++)
{
SOCKET OneSocket;

sockaddr_in UpsAddr;
WSADATA wsaData;

DWORD Ret;
if ((Ret = WSAStartup(0x0202, &wsaData)) != 0)//WSAStartup 调用Socket前必须指定版本
{
printf("WSAStartup failed with error %d\n", Ret);
continue;
}

// Create a listening socket
if ((OneSocket = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, //流的方式创建Sock
WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET)
{
printf("WSASocket() failed with error %d\n", WSAGetLastError());
continue;
}

UpsAddr.sin_family = AF_INET;//固定的
UpsAddr.sin_addr.s_addr = inet_addr(g_connections[index].IP);
UpsAddr.sin_port = htons(100);//htons 网络字节序


unsigned long desIP = UpsAddr.sin_addr.S_un.S_addr;//四字节ip形式
BYTE * pIp = (BYTE *)&desIP;
BYTE ip1 = *pIp;
BYTE ip2 = *(pIp+1);
BYTE ip3 = *(pIp+2);
BYTE ip4 = *(pIp+3);

//设置超时
BOOL bOptVal = TRUE;
int bOptLen = sizeof(BOOL),iOptVal =2,iOptLen = sizeof(int);
if (setsockopt(OneSocket, SOL_SOCKET, SO_SNDTIMEO, (char*)&bOptVal, bOptLen) == SOCKET_ERROR)
{
printf("设置超时失败!\n");
continue;
}
if (setsockopt(OneSocket, SOL_SOCKET, SO_RCVTIMEO, (char*)&bOptVal, bOptLen) == SOCKET_ERROR)
{
printf("设置超时失败!\n");
continue;
}

//设置非阻塞方式连接
unsigned long ul = 1;
int ret = ioctlsocket(OneSocket, FIONBIO, (unsigned long*)&ul);
if(ret==SOCKET_ERROR)
continue;

connect(OneSocket,(sockaddr *)&UpsAddr,sizeof(UpsAddr)); //连接

//select 模型,即设置超时
struct timeval timeout ;
fd_set r;

FD_ZERO(&r);
FD_SET(OneSocket, &r);
timeout.tv_sec = 0;
timeout.tv_usec =iTimeOutConn;//连接超时,微妙
ret = select(0, 0, &r, 0, &timeout);
if ( ret <= 0 )
{
closesocket(OneSocket);

printf("%s连接失败!%d\n",g_connections[index].IP,WSAGetLastError());

continue;
}

//一般非锁定模式套接比较难控制,可以根据实际情况考虑 再设回阻塞模式
unsigned long ul1= 0 ;
ret = ioctlsocket(OneSocket, FIONBIO, (unsigned long*)&ul1);
if(ret==SOCKET_ERROR)
{
closesocket (OneSocket);
continue;
}

const char * Cmd = "UPSLOG";
int iSucessS = send(OneSocket,Cmd, 6, 0);//发指令
int iSucessR = recv(OneSocket, DataBuff, 1024, 0);//读数据

if(iSucessR == -1 && iSucessR == 0)//没有接收到数据
{
if (closesocket(OneSocket) == SOCKET_ERROR)//关闭连接
{
printf("closesocket() failed with error %d\n", WSAGetLastError());
continue;
}

WSACleanup();

continue;
}

//帧尾加UPS的ip
CHAR * UpsIp =GetIP(OneSocket);
CHAR * temp = "-";
strcat(DataBuff,temp);
strcat(DataBuff,UpsIp);
CHAR * temp2= "EE";
strcat(DataBuff,temp2);

if (closesocket(OneSocket) == SOCKET_ERROR)//关闭连接
{
printf("closesocket() failed with error %d\n", WSAGetLastError());
continue;
}

WSACleanup();

/* 转发 */
int iSucessOctopus = send(m_CatchSocket,DataBuff, 1024, 0);

/* 没发送成功,重连 */
if(iSucessOctopus == -1)
{
WSACleanup();

if (WSAStartup(0x0202, &wsaData) != 0)
{
printf("WSAStartup failed with error\n" );
return ;
}

// Create a listening socket
if ((m_CatchSocket = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0,
WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET)
{
printf("WSASocket() failed with error %d\n", WSAGetLastError());
return ;
}

if(connect(m_CatchSocket,(sockaddr *)&m_OctopusAddr,sizeof(m_OctopusAddr)) == -1)
{
printf("重新连接Socket失败!%d\n",WSAGetLastError());
continue ;
}
else
{ /* 重新发送 发送是否成功不做判断 */
iSucessOctopus = send(m_CatchSocket,DataBuff, 1024, 0);
}
}

g_connections[index].times ++;//做计数

memset(DataBuff,'\0',1024);
}

//计时是否到三十秒//系统时间//计时
SYSTEMTIME NewTime;
GetLocalTime(&NewTime);

WORD iC = (NewTime.wMinute-OldTime.wMinute) *60 + (NewTime.wSecond-OldTime.wSecond);
if( iC<30)
{
Sleep((30- iC) * 1000);//延迟
}
else
{
continue;
}

}
}
...全文
439 20 打赏 收藏 转发到动态 举报
写回复
用AI写文章
20 条回复
切换为时间正序
请发表友善的回复…
发表回复
warriormark 2010-02-09
  • 打赏
  • 举报
回复
一个线程里面for 循环8次么?
可不可以开 8个线程试试
疯魔症 2010-02-09
  • 打赏
  • 举报
回复

void CatchUpsMake(bool bFlag)
{
char DataBuff[1024]; //缓存
memset(DataBuff,'\0',1024);

printf("开始循环读取数据!\n");

while(bFlag)
{
//计时
SYSTEMTIME OldTime;
GetLocalTime(&OldTime);

TCHAR * config_dir = getAppConfigDir();//每30秒循环时,读一次config.ini文件
int iTimeOutConn = GetPrivateProfileInt(L"Time Out",L"TimeOutConn",2000,config_dir);
int iTimeOutSend = GetPrivateProfileInt(L"Time Out",L"TimeOutSend",2000,config_dir);
int iTimeOutRecv = GetPrivateProfileInt(L"Time Out",L"TimeOutRecv",2000,config_dir);

if(0 == iTimeOutConn)
{
printf("读取连接超时失败,将使用默认超时!\n");
iTimeOutConn = 2000;
}

if(0 == iTimeOutSend)
{
printf("读取发送超时失败,将使用默认超时!\n");
iTimeOutSend = 2000;
}

if(0 == iTimeOutRecv)
{
printf("读取接收超时失败,将使用默认超时!\n");
iTimeOutRecv = 2000;
}

printf("\n");
for (DWORD index=0; index<g_connections.size(); index++)
{
SOCKET OneSocket;

sockaddr_in UpsAddr;
WSADATA wsaData;

DWORD Ret;

if ((OneSocket = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, //流的方式创建Sock
WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET)
{
printf("WSASocket() failed with error %d\n", WSAGetLastError());
continue;
}

UpsAddr.sin_family = AF_INET;//固定的
UpsAddr.sin_addr.s_addr = inet_addr(g_connections[index].IP);
UpsAddr.sin_port = htons(100);//htons 网络字节序

//设置超时
BOOL bOptVal = TRUE;
int bOptLen = sizeof(BOOL),iOptVal =2,iOptLen = sizeof(int);
if (setsockopt(OneSocket, SOL_SOCKET, SO_SNDTIMEO, (char*)&bOptVal, bOptLen) == SOCKET_ERROR)
{
printf("设置超时失败!\n");
continue;
}
if (setsockopt(OneSocket, SOL_SOCKET, SO_RCVTIMEO, (char*)&bOptVal, bOptLen) == SOCKET_ERROR)
{
printf("设置超时失败!\n");
continue;
}

//设置非阻塞方式连接
unsigned long ul = 1;
int ret = ioctlsocket(OneSocket, FIONBIO, (unsigned long*)&ul);
if(ret==SOCKET_ERROR)
continue;

connect(OneSocket,(sockaddr *)&UpsAddr,sizeof(UpsAddr)); //连接

//select 模型,即设置超时
struct timeval timeout ;
fd_set r;

FD_ZERO(&r);
FD_SET(OneSocket, &r);
timeout.tv_sec = 0;
timeout.tv_usec =iTimeOutConn;//连接超时,微妙
ret = select(0, 0, &r, 0, &timeout);
if ( ret <= 0 )
{
closesocket(OneSocket);

printf("%s连接失败!%d\n",g_connections[index].IP,WSAGetLastError());

continue;
}

//一般非锁定模式套接比较难控制,可以根据实际情况考虑 再设回阻塞模式
unsigned long ul1= 0 ;
ret = ioctlsocket(OneSocket, FIONBIO, (unsigned long*)&ul1);
if(ret==SOCKET_ERROR)
{
closesocket (OneSocket);
continue;
}

const char * Cmd = "UPSLOG";
int iSucessS = send(OneSocket,Cmd, 6, 0);//发指令
int iSucessR = recv(OneSocket, DataBuff, 1024, 0);//读数据

if(iSucessR == -1 && iSucessR == 0)//没有接收到数据
{
if (closesocket(OneSocket) == SOCKET_ERROR)//关闭连接
{
printf("closesocket() failed with error %d\n", WSAGetLastError());
continue;
}
continue;
}

//帧尾加UPS的ip
CHAR * UpsIp =GetIP(OneSocket);
CHAR * temp = "-";
strcat(DataBuff,temp);
strcat(DataBuff,UpsIp);
CHAR * temp2= "EE";
strcat(DataBuff,temp2);

if (closesocket(OneSocket) == SOCKET_ERROR)//关闭连接
{
printf("closesocket() failed with error %d\n", WSAGetLastError());
continue;
}


/* 转发 */
int iSucessOctopus = send(m_CatchSocket,DataBuff, 1024, 0);

/* 没发送成功,重连 */
if(iSucessOctopus == -1)
{
if ((m_CatchSocket = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0,
WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET)
{
printf("WSASocket() failed with error %d\n", WSAGetLastError());
return ;
}

if(connect(m_CatchSocket,(sockaddr *)&m_OctopusAddr,sizeof(m_OctopusAddr)) == -1)
{
printf("重新连接Socket失败!%d\n",WSAGetLastError());
continue ;
}
else
{ /* 重新发送 发送是否成功不做判断 */
iSucessOctopus = send(m_CatchSocket,DataBuff, 1024, 0);
}
}

g_connections[index].times ++;//做计数

memset(DataBuff,'\0',1024);
}

//计时是否到三十秒//系统时间//计时
SYSTEMTIME NewTime;
GetLocalTime(&NewTime);

WORD iC = (NewTime.wMinute-OldTime.wMinute) *60 + (NewTime.wSecond-OldTime.wSecond);
if( iC < MAX_INTERVAL_TIME)
{
Sleep((MAX_INTERVAL_TIME- iC) * 1000);//延迟
}
else
{
continue;
}

}
}
疯魔症 2010-02-09
  • 打赏
  • 举报
回复
服务器那边是单片机cp2200。。。 用tcp测试工具都能连上,收发数据
引用 11 楼 warriormark 的回复:
引用 8 楼 zwb0540822 的回复:我是在连接时出的这个错误呀。现在装了8台设备了,30秒遍历的时候,有时候能连上五六台,有时候只能连上一台,要过年回家呀,郁闷了。
一个端口肯定可以连接多台Client,对应不同的clinet的是socket,不是端口
每30秒,都同时Connect服务器?
服务器那边用什么来响应connect操作?是线程 还是 接受WM_SOCKET消息?
warriormark 2010-02-09
  • 打赏
  • 举报
回复

/* 在头文件中定义消息响应函数 */

afx_msg void OnSocket(WPARAM wParam, LPARAM lParam);

/* cpp 中 */
#define WM_SOCKET WM_USER+100 //定义WM_SOCKET消息

BEGIN_MESSAGE_MAP()

ON_MESSAGE(WM_SOCKET,OnSocket) //关联消息和相应函数
END_MESSAGE_MAP()


SOCKET m_socket;//侦听的socket
SOCKET ClientSocket;//用来保存连接上的客户端的Socket
sockaddr_in remoteClient;//用来保存连接上的客户端地址

m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
bind(m_socket,(sockaddr*)&serverAddr,sizeof(serverAddr));//绑定端口
listen(m_socket,5);//开始侦听

WSAAsyncSelect(m_socket, m_hWnd,
WM_SOCKET, FD_ACCEPT );//通知窗口,接收WM_SOCKET消息

OnSocket(WPARAM wParam, LPARAM lParam)
{

SOCKET s = wParam;
int pSize = sizeof(remoteClient);
switch(WSAGETSELECTEVENT(lParam))
{
case FD_ACCEPT:
{
ClientSocket = accept(s,(sockaddr*)&remoteClient,&pSize);



break;
}



}


warriormark 2010-02-09
  • 打赏
  • 举报
回复
引用 8 楼 zwb0540822 的回复:
我是在连接时出的这个错误呀。
现在装了8台设备了,30秒遍历的时候,有时候能连上五六台,有时候只能连上一台,要过年回家呀,郁闷了。

一个端口肯定可以连接多台Client,对应不同的clinet的是socket,不是端口
每30秒,都同时Connect服务器?
服务器那边用什么来响应connect操作?是线程 还是 接受WM_SOCKET消息?
疯魔症 2010-02-09
  • 打赏
  • 举报
回复
情况比较复杂,系统改了又改的,最早是设备往服务器传数据的,现在改成服务器主动取数据。

引用 9 楼 wizardk 的回复:
从你的业务流程上来看,你问什么不用UDP广播或组播呢?
1.	添加通讯线程,使用tcp协议发送命令字,主动从UPS控制器取数据。
2. 得到数据后在帧尾添加UPS控制器IP转发给本机6018端口。(Ip为4字节或字符串形式)
3. 原通讯程序可以不动,尽量减小变动。(帧内容解析时,解析出ip)


Main()
{
…..
//原通讯线程打开之后,延迟十秒开启本通讯线程Thread()
}

Thread
Sleep(10 * 1000) //延迟10秒
m_Socket =new Socket(local,6018)//和本地的连接

try
m_Socket.connect();
bFlag = true;
While(bFlag) //死循环,单独写成函数
Time = dataTime.now.//本次遍历开始的时间,遍历结束时判断是否超过30秒,不到30秒的延迟到30秒。
For(int i=0;i< g_connectons.size;i++)
try
Ip = g_conections[i].ip;
OneSocket = new Socket(Ip,100) //连接控制器
If(OneSocket.connect)
OneSocket.Send(“UPSLOG”); //发指令
OneSocket.Read(Data); //读应答
OneSocket.Close();
Data += ip;
M_Socket.Send(Data) //转发本地6018端口
Else
//连接不成功
Catch
//没有连接成功
End For
//判断时间是否到30秒做延迟
End While
Catch
//和本地的连接失败
WizardK 2010-02-09
  • 打赏
  • 举报
回复
从你的业务流程上来看,你问什么不用UDP广播或组播呢?
疯魔症 2010-02-09
  • 打赏
  • 举报
回复
我是在连接时出的这个错误呀。
现在装了8台设备了,30秒遍历的时候,有时候能连上五六台,有时候只能连上一台,要过年回家呀,郁闷了。

引用 6 楼 cchvsgame 的回复:
10035的错误,一个非阻塞的Socket调用中,由于没有可接受的数据(如接受端系统缓冲没有数据或发送端系统缓冲区已满),因此调用返回WSAWOULDBLOCK错误,这并不是一个致命的错误,你可以接着调用
疯魔症 2010-02-09
  • 打赏
  • 举报
回复
问题解决了,设置超时的地方问题,把
timeout.tv_sec = 0;
timeout.tv_usec =iTimeOutConn;//连接超时,微妙
改为秒就可以了,以前可能是微妙的超时没起作用,现在可以了,谢谢所有关注的人。
祝所有人新年快乐,身体健康
wuhuwy 2010-02-09
  • 打赏
  • 举报
回复
引用 6 楼 cchvsgame 的回复:
10035的错误,一个非阻塞的Socket调用中,由于没有可接受的数据(如接受端系统缓冲没有数据或发送端系统缓冲区已满),因此调用返回WSAWOULDBLOCK错误,这并不是一个致命的错误,你可以接着调用
正解
cchvsgame 2010-02-09
  • 打赏
  • 举报
回复
10035的错误,一个非阻塞的Socket调用中,由于没有可接受的数据(如接受端系统缓冲没有数据或发送端系统缓冲区已满),因此调用返回WSAWOULDBLOCK错误,这并不是一个致命的错误,你可以接着调用
疯魔症 2010-02-09
  • 打赏
  • 举报
回复
我把所有的超时都去掉,下午去客户那看还出问题不,
疯魔症 2010-02-09
  • 打赏
  • 举报
回复
不是这样,大概一百多台设备,循环一百多个ip去取数据,程序写在一个for里面了
引用 15 楼 warriormark 的回复:
一个线程里面for 循环8次么?
可不可以开 8个线程试试
klkvc386 2010-02-09
  • 打赏
  • 举报
回复
Mark...............
疯魔症 2010-02-08
  • 打赏
  • 举报
回复
谢三楼四楼,回去试下
xwsn007 2010-02-06
  • 打赏
  • 举报
回复
同意楼上的
精锐掷矛手 2010-02-05
  • 打赏
  • 举报
回复

sockaddr_in UpsAddr;
WSADATA wsaData;

DWORD Ret;
if ((Ret = WSAStartup(0x0202, &wsaData)) != 0)//WSAStartup 调用Socket前必须指定版本
{
printf("WSAStartup failed with error %d\n", Ret);
continue;
}


程序开始时加载winsock,退出时WSAClean。
循环中不要每次都加载释放,是不是好点。
宇帆 2010-02-05
  • 打赏
  • 举报
回复
同一个端口 不能连接多个客户端吗?
bragi523 2010-02-05
  • 打赏
  • 举报
回复
你用同一个端口来连接吗?
一个端口不能同时建多个TCP连接


假如你是每次都close掉前一个再连后一个的话,就试试设置socket地址可重用属性,并且在连接之前shutdown

18,356

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 网络编程
c++c语言开发语言 技术论坛(原bbs)
社区管理员
  • 网络编程
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧