用MFC编写TCP通讯问题?

严。。。 2014-08-11 09:11:00
想用MFC做客户端的TCP通讯(工业上的,与PLC通讯),因为是初学者,所以希望大家多多指教!

void CPLCconnectDlg::OnBnClickedConnect()
{
CString strIP(L"192.168.2.15");
if(!PLC_1.Create())
{
AfxMessageBox(L"创建失败!");
return;
}
if(PLC_1.Connect(strIP, 1234))
{
AfxMessageBox(L"连接成功!");
pTread = AfxBeginThread(ThreadFunc, &Info);
}
}

问题:
1.如果服务器没有启动,点了按钮后会出现死机状况,我知道问题出在Connect()这个函数上,但是不知道怎么解决,麻烦各位详细解释下。
2.Create()创建后,如果再点按钮,会弹出错误来,怎么加个条件(判断创建后就不创建了)?
3.CSocket里面有没有函数可以判断是否连接上? MSDN里面没有查到

谢谢啦!

...全文
229 18 打赏 收藏 转发到动态 举报
写回复
用AI写文章
18 条回复
切换为时间正序
请发表友善的回复…
发表回复
阿源是少年 2014-08-12
  • 打赏
  • 举报
回复
select模型我也用过,不过貌似只能设置send 和 recv 超时,连接超时没用
阿源是少年 2014-08-12
  • 打赏
  • 举报
回复
引用 10 楼 yan8296798 的回复:
[quote=引用 8 楼 pcradio 的回复:] #define USER_CONNECT_OK WM_USER+100 // 自定义消息,表示连接成功 #define USER_CONNECT_FAIL WM_USER+101 // 连接失败 UINT ProcConnectServer(LPVOID lpParam) { HWND hWnd = (HWND)lpParam; CString strIP(L"192.168.2.15"); BOOL b = PLC_1.Connect(strIP, 1234); // 这里你需要把PLC_1设置为全局变量, // 若服务器无回应,此时已经阻塞 if(b) PostMessage(hWnd, USER_CONNECT_OK, NULL, NULL); // 连接成功后就往UI线程发送自定义消息表示连接成功 else PostMessage(hWnd, USER_CONNECT_FAIL, NULL, NULL); // 连接失败 return 0; }
谢谢你这么详细的解释,其一,我想在主线程里面可以实时判断连接是否成功,其二,连接开了一个线程,那我接受和发送数据应该再开一个线程吗? 应该返回主线程开接收和发送的线程吧?[/quote] 连接成功后,接收发送可以分别一个线程,也可以共用一个线程,这个线程你可以直接在连接线程里面开,也可以在主线程收到连接响应消息后再开,都可以。你要在主线程实时判断是否连接,只能通过全局 变量g_bConnected了,连接成功就令g_bConnect = TRUE;主线程读取g_bConnect就知道是否连接成功了
严。。。 2014-08-12
  • 打赏
  • 举报
回复
引用 8 楼 pcradio 的回复:
#define USER_CONNECT_OK WM_USER+100 // 自定义消息,表示连接成功 #define USER_CONNECT_FAIL WM_USER+101 // 连接失败 UINT ProcConnectServer(LPVOID lpParam) { HWND hWnd = (HWND)lpParam; CString strIP(L"192.168.2.15"); BOOL b = PLC_1.Connect(strIP, 1234); // 这里你需要把PLC_1设置为全局变量, // 若服务器无回应,此时已经阻塞 if(b) PostMessage(hWnd, USER_CONNECT_OK, NULL, NULL); // 连接成功后就往UI线程发送自定义消息表示连接成功 else PostMessage(hWnd, USER_CONNECT_FAIL, NULL, NULL); // 连接失败 return 0; }
谢谢你这么详细的解释,其一,我想在主线程里面可以实时判断连接是否成功,其二,连接开了一个线程,那我接受和发送数据应该再开一个线程吗? 应该返回主线程开接收和发送的线程吧?
严。。。 2014-08-12
  • 打赏
  • 举报
回复
引用 7 楼 VisualEleven 的回复:
可以用select模型来设置connect连接超时~
//设置非阻塞方式连接 unsigned long ul = 1; int ret; ret = ioctlsocket(m_sockTCP, FIONBIO, (unsigned long*)&ul); if(ret == SOCKET_ERROR) return FALSE; //连接 connect(m_sockTCP,(struct sockaddr *)&server,sizeof(server)); //select 模型,即设置超时 struct timeval timeout ; fd_set r; FD_ZERO(&r); FD_SET(m_sockTCP, &r); timeout.tv_sec = 5; //连接超时 timeout.tv_usec =0; ret = select(0, 0, &r, 0, &timeout); if ( ret <= 0 ){ ::closesocket(m_sockTCP); return FALSE; } 尝试用这个方法试过,可是没有效果
阿源是少年 2014-08-12
  • 打赏
  • 举报
回复
#define USER_CONNECT_OK WM_USER+100 // 自定义消息,表示连接成功 #define USER_CONNECT_FAIL WM_USER+101 // 连接失败 UINT ProcConnectServer(LPVOID lpParam) { HWND hWnd = (HWND)lpParam; CString strIP(L"192.168.2.15"); BOOL b = PLC_1.Connect(strIP, 1234); // 这里你需要把PLC_1设置为全局变量, // 若服务器无回应,此时已经阻塞 if(b) PostMessage(hWnd, USER_CONNECT_OK, NULL, NULL); // 连接成功后就往UI线程发送自定义消息表示连接成功 else PostMessage(hWnd, USER_CONNECT_FAIL, NULL, NULL); // 连接失败 return 0; }
Eleven 2014-08-12
  • 打赏
  • 举报
回复
可以用select模型来设置connect连接超时~
阿源是少年 2014-08-12
  • 打赏
  • 举报
回复
2. 关于阻塞问题 Connect是阻塞的,如果服务器没有接受连接,将会阻塞,可以通过BOOL IsBlocking()来判断是否阻塞,你想实时判断是否连接,也只能通过设置一个全局变量,没有API直接判断是否连接的,死机就是因为阻塞了,你应该把Connect操作放在一个线程里去连,而不是放在UI线程里,当连上了,你就把全局变量设为g_bConnected = TRUE,然后向主线程发送一个窗口消息,可以是自定义的消息,通知连接成功,你可以在主线程里设置一个Timer监控全局变量g_bConnected 是否为TRUE,如果超过指定时间,就调CancelBlockingCall()强制取消阻塞,这时connect线程就会退出
阿源是少年 2014-08-12
  • 打赏
  • 举报
回复
1.关于创建后不在创建问题,Create创建套接字成功后返回值是非零的,如果是0就表示失败了,你设置一个全局变量吧,创建成功
后设置一个标志,这样下次就不会再Create(),其实你这种逻辑只适合做一个客户端连接,貌似你的CSocket对象是一个成员或者全局变量:代码如下
BOOL g_bCreated = FALSE; // 全局变量

void CPLCconnectDlg::OnBnClickedConnect()
{
CString strIP(L"192.168.2.15");
if(!g_bCreated)
{
if(!PLC_1.Create())
{
AfxMessageBox(L"创建失败!");
return;
}
g_bCreated = TRUE;
}
//if(PLC_1.Connect(strIP, 1234))
//{
// AfxMessageBox(L"连接成功!");
// pTread = AfxBeginThread(ThreadFunc, &Info);
//}
}

严。。。 2014-08-12
  • 打赏
  • 举报
回复
引用 3 楼 JoeBlackzqq 的回复:
1. 不管你改成什么值都一样呀,因为你是卡在主线程,所以在超时前,这个程序是动不了的。而且完全没有必要去改这个值,因为大家都是这么用的,同样解决了问题。你可以将这个连接的过程放到线程里,即非主线程里。或者用异步socket来处理 2. 要学会使用MSDN或其他帮助文档,对自己所使用的函数原型都不清楚,做什么开发呢?不管你在哪里判断,可以搞个变量,这个变量在函数内外都能访问不就可以了吗?
我指的是实时判断是否连接了服务器,想一直判断啊
JoeBlackzqq 2014-08-12
  • 打赏
  • 举报
回复
1. 不管你改成什么值都一样呀,因为你是卡在主线程,所以在超时前,这个程序是动不了的。而且完全没有必要去改这个值,因为大家都是这么用的,同样解决了问题。你可以将这个连接的过程放到线程里,即非主线程里。或者用异步socket来处理 2. 要学会使用MSDN或其他帮助文档,对自己所使用的函数原型都不清楚,做什么开发呢?不管你在哪里判断,可以搞个变量,这个变量在函数内外都能访问不就可以了吗?
严。。。 2014-08-12
  • 打赏
  • 举报
回复
引用 17 楼 pcradio 的回复:
检测服务器与客户机之间的连接问题,你如果是长连接的话,应该有心跳包机制的,关于心跳包机制,你可以百度一下,这样就能实时检测到服务器与客户机之间的连接情况
谢谢!
阿源是少年 2014-08-12
  • 打赏
  • 举报
回复
检测服务器与客户机之间的连接问题,你如果是长连接的话,应该有心跳包机制的,关于心跳包机制,你可以百度一下,这样就能实时检测到服务器与客户机之间的连接情况
严。。。 2014-08-12
  • 打赏
  • 举报
回复
引用 15 楼 pcradio 的回复:
[quote=引用 14 楼 yan8296798 的回复:] [quote=引用 12 楼 pcradio 的回复:] select模型我也用过,不过貌似只能设置send 和 recv 超时,连接超时没用
实时的话需要一直调用Connect这个函数来判断是否连接成功吗? 我之前以为调用一次就可以了[/quote] Connect 只需要调用一次就够了,再调会返回错误,你通过全局变量就可以判断是否连接成功了啊,当你关闭了 socket,你再把全局变量设为g_bConnected = FALSE就行了[/quote] 但是连接成功后,如果突然服务器故障了,那g_bConnected 仍然是true啊
阿源是少年 2014-08-12
  • 打赏
  • 举报
回复
引用 14 楼 yan8296798 的回复:
[quote=引用 12 楼 pcradio 的回复:] select模型我也用过,不过貌似只能设置send 和 recv 超时,连接超时没用
实时的话需要一直调用Connect这个函数来判断是否连接成功吗? 我之前以为调用一次就可以了[/quote] Connect 只需要调用一次就够了,再调会返回错误,你通过全局变量就可以判断是否连接成功了啊,当你关闭了 socket,你再把全局变量设为g_bConnected = FALSE就行了
严。。。 2014-08-12
  • 打赏
  • 举报
回复
引用 12 楼 pcradio 的回复:
select模型我也用过,不过貌似只能设置send 和 recv 超时,连接超时没用
实时的话需要一直调用Connect这个函数来判断是否连接成功吗? 我之前以为调用一次就可以了
JoeBlackzqq 2014-08-12
  • 打赏
  • 举报
回复
楼上的各位都很热心呀,这些答案已经足够解决你的问题了,好好领悟下吧!
严。。。 2014-08-11
  • 打赏
  • 举报
回复
引用 1 楼 JoeBlackzqq 的回复:
1. 会出现死机,其实是在等待超时,默认好像是15秒吧? 2. 创建后,可以搞个标志,下次再进这个函数时,先判断是否已创建,如果没创建,再去创建。 3. 你这是阻塞式连接,Connect本身就有返回值,看下返回值的含义就知道答案了!
1.怎么更改这个值,没有其他的办法么,出现等待画面会卡着诶,希望解释的详细点,谢谢 2.这个明白了, 3.我想在函数外部判断,CSocket类里面有这种功能的函数吗?
JoeBlackzqq 2014-08-11
  • 打赏
  • 举报
回复
1. 会出现死机,其实是在等待超时,默认好像是15秒吧? 2. 创建后,可以搞个标志,下次再进这个函数时,先判断是否已创建,如果没创建,再去创建。 3. 你这是阻塞式连接,Connect本身就有返回值,看下返回值的含义就知道答案了!

18,356

社区成员

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

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