多人聊天室 服务器端OnReceive无法触发

maomao85 2013-12-30 04:54:33
我用CSocket写了个基于MFC的多人聊天室程序。可是当我多次点击客户端的发送按钮时,刚开始服务器端可以受到客户端发送的消息,可是当客户端发送多次后,服务器就收不到了。(经我调试发现是服务器端的OnReceive没有触发。我反复测试,有时候是客户端发5 6次,服务器就收不到;有时候是客户端发几十次后,服务器才收不到)。
我的服务器有CServerSocket类和CClientSocket类,都是派生于CSocket

客户端发送消息代码如下:

void CChatDlg::OnSend()
{
UpdateData();
Header header;
header.command=COMMAND_SEND;
header.datalen=m_sendmsg.GetLength();
pSocket->Send((char *)&header,sizeof(header));
USES_CONVERSION;
pSocket->Send(W2A(m_sendmsg),m_sendmsg.GetLength());
//在客户端的edit控件区域显示聊天信息
CString temp=_T("");
temp+=m_sendmsg;
temp+=_T("\r\n");
temp+=msg;
m_controledit.SetWindowText(temp);
}


服务器端接受客户端连接代码:

void CServerSocket::OnAccept(int nErrorCode)
{
CClientSocket *clientsocket;
clientsocket=new CClientSocket(&m_listconnect);
this->Accept(*clientsocket);
clientsocket->pdlg=this->pdlg;
m_listconnect.push_back(clientsocket);
this->pdlg->ShowMsg(_T("connect"));
CSocket::OnAccept(nErrorCode);
}


服务器端接受客户端消息代码:

void CClientSocket::OnReceive(int nErrorCode)
{

CHAR buff[sizeof(Header)];
memset(buff, 0, sizeof(buff));
Receive(buff,sizeof(buff)); //先接收包头
Header *header = (Header*)buff;
DWORD length = header->datalen;
BYTE type = header->command;

CHAR *message=new CHAR[length+1];//根据包头里面定义的包体长度,来接收包体
memset(message, 0, length+1);
Receive(message,length);

switch(type)
{
case COMMAND_REG:
{
Header head;
head.command=REG_SUCCESS;
head.datalen=0;
this->Send((char*)&head,sizeof(head));
}
break;
case COMMAND_LOGIN:
{
Header head;
head.command=LOGIN_SUCCESS;
head.datalen=0;
this->Send((char*)&head,sizeof(head));
}
break;
case COMMAND_SEND:
{
USES_CONVERSION;
this->pdlg->ShowMsg(A2W(message));
}
break;
default:
{

}
}
return CSocket::OnReceive(nErrorCode);
}
...全文
670 102 打赏 收藏 转发到动态 举报
写回复
用AI写文章
102 条回复
切换为时间正序
请发表友善的回复…
发表回复
brk1985 2014-01-14
  • 打赏
  • 举报
回复
引用 93 楼 maomao85 的回复:
[quote=引用 92 楼 brk1985 的回复:] FD_CLOSE|FD_READ|FD_WRITE分别是关闭事件、读事件、写事件,对应函数是OnClose、OnReceive、OnSend。貌似CSocket触发机制封装好了,不用该语句也行。具体也理解不深,看看其他层怎么说。。。继续关注。 参考资料: 我这几天都在玩socket编程,很有意思啊! asyncSelect的作用是让socket成为异步的(非阻塞), 当指定的socket事件到达时(FD_CLOSE,FD_READ,FD_WRITE...) 对指定的window发出一个自定义的消息(WM_USER+1xx) 其中消息参数指定了事件类型便于处理。 所以如果用异步方式就不用多线程啦! 如果用多线程就用阻塞方式,因为在阻塞方式下读写是你自己控制的。 http://bbs.csdn.net/topics/23
你有没有像在他的源码基础上加多线程呢? 我下午在公司在发送端循环发送100次,发现只发了3次就断了~~[/quote] 这个demo没有解决你标题所说的问题,也会出现同样问题,也很难找到解决方法,可能是很多人放弃CSocket的原因吧。话说,你现在这个问题解决了吗?
maomao85 2014-01-14
  • 打赏
  • 举报
回复
引用 99 楼 GLSC_CENA 的回复:
结贴吧,这个帖子够长了,有问题再开贴
我开了新帖子,指导下http://bbs.csdn.net/topics/390693375
maomao85 2014-01-13
  • 打赏
  • 举报
回复
引用 99 楼 GLSC_CENA 的回复:
结贴吧,这个帖子够长了,有问题再开贴
额,那我开个帖子问问同步~~
这个娜戒海了 2014-01-13
  • 打赏
  • 举报
回复
结贴吧,这个帖子够长了,有问题再开贴
maomao85 2014-01-13
  • 打赏
  • 举报
回复
引用 97 楼 GLSC_CENA 的回复:
貌似CSocket的确不支持跨线程,需要先Detach,用Socket才可以多线程 你先做吧,做完了再说
关于数据同步的问题呢? 比如2个线程同时访问数据库的某张表,要进行读写,怎么办?
这个娜戒海了 2014-01-13
  • 打赏
  • 举报
回复
貌似CSocket的确不支持跨线程,需要先Detach,用Socket才可以多线程 你先做吧,做完了再说
maomao85 2014-01-12
  • 打赏
  • 举报
回复
引用 95 楼 GLSC_CENA 的回复:
    HANDLE handle=NULL;     handle=_beginthread((void)mufun,NULL,(LPVOID)this);     if(handle == NULL)     {         return ;     }          CloseHandle(handle); 线程开了以后,你就CloseHandle,问题在这。这个handle你不需要管,线程结束以后会自己销毁的 线程刚开始跑你就主动关闭了
我在网上看说要销毁这个句柄,释放内核对象啊~~ 我后来换成用_beginthreadex了~~ 但是CSocket不能跨线程,这是我遇到的新问题,线程倒运行起来了,结果跨线程又报错~~ 我决定还是用SOCKET API好了,然后单独建立线程用来listen,然后收发数据?
这个娜戒海了 2014-01-12
  • 打赏
  • 举报
回复
    HANDLE handle=NULL;     handle=_beginthread((void)mufun,NULL,(LPVOID)this);     if(handle == NULL)     {         return ;     }          CloseHandle(handle); 线程开了以后,你就CloseHandle,问题在这。这个handle你不需要管,线程结束以后会自己销毁的 线程刚开始跑你就主动关闭了
这个娜戒海了 2014-01-12
  • 打赏
  • 举报
回复
线程函数能进去否 还是直接报错了 你试试AfxBeginThread 发我邮箱吧 另外,不建议从一台机器上进行首发,最好找两台机器做测试,或者开一台虚拟机
brk1985 2014-01-10
  • 打赏
  • 举报
回复
还在继续,加油。。。也比较关注,网络这块也比较菜鸟,公司项目也没怎么涉及网络编程。。。 郑阿奇的《Visual C++网络编程(含CD光盘1张)》第3章 即时通信:网络聊天软件 有介绍CSocket实现的版本。。。源码 论坛下载有,可以去找找。 该聊天室程序比你的版本只多了一点内容, 思路大概是在 包头结构体header添加长度、类型(用户登录或发送聊天信息)2个成员,,,连接的时候和发送聊天信息一样,同时发送2个包,一个header包、一个“用户名”包,用户名用于区分socket,,,服务器socket(CClientSocket类)的OnReceive函数(判别是登录还是发送信息,登录则接收用户名包,否则接收的是发送聊天信息)接收这个包,就可以保存该客户端的用户名。。。47楼说的标示名就是大概类似用户名的。 郑阿奇的版本,服务器端2个socket类,CServerSocket类是监听socket类、CClientSocket类是为每个客户端分配的socket类。CServerSocket类中一个客户端new一个CClientSocket类对象,并用链表存储。
maomao85 2014-01-10
  • 打赏
  • 举报
回复
引用 82 楼 GLSC_CENA 的回复:
他给你推荐了两本书,建议去下载电子版的看一下
还有对于服务器的程序,线程是怎么同步的呢?比如服务器的2个线程都连接到了数据库,都要对数据库中的表A进行写,这个时候怎么同步? 是用关键代码段?例如: EnterCriticalSection(criticalsection); // 线程对表A进行写 ... LeaveCriticalSection(criticalsection);
这个娜戒海了 2014-01-10
  • 打赏
  • 举报
回复
引用 87 楼 maomao85 的回复:
[quote=引用 67 楼 GLSC_CENA 的回复:] OnReceive返回了,线程不受影响,要等到执行完才会退出的,建议你还是多学点基础内容
亲 你说一个OnReceive开一个请求,那不是多个并发请求就并发很多线程??这合理吗? [/quote] 的确不合理,但是对付小型的聊天室足够了,并且要基于你现阶段对CSOCKET的李戒 你如果需要更合理的,建议使用IOCP或者ACE或者libevent其他模型 我在53楼已经和你说过了
maomao85 2014-01-10
  • 打赏
  • 举报
回复
引用 67 楼 GLSC_CENA 的回复:
OnReceive返回了,线程不受影响,要等到执行完才会退出的,建议你还是多学点基础内容
亲 你说一个OnReceive开一个请求,那不是多个并发请求就并发很多线程??这合理吗?
maomao85 2014-01-10
  • 打赏
  • 举报
回复
引用 85 楼 brk1985 的回复:
我只写了一本《Visual C++网络编程(含CD光盘1张)》,我也在用,感觉内容很基础,对网络编程刚刚入门的读者可以有初步提升。据说<Windows网络编程>第二版 这本也很好,买的人很多,当当上一直缺货,还没买到。另外《WinSock网络编程经络》据说也很好,这本还没怎么看。 Visual C++网络编程案例实战(配... ¥48.60 1 ¥35.40 VIP——WinSock网络编程经络 ¥32.10 1 ¥29.50 Visual C++网络编程开发与实战(配光盘) Visual C++网络编程(含CD光盘1张) 买过四本网络编程的书,也就郑阿奇的最后一本看得最多
十分感谢~~
maomao85 2014-01-10
  • 打赏
  • 举报
回复
引用 92 楼 brk1985 的回复:
FD_CLOSE|FD_READ|FD_WRITE分别是关闭事件、读事件、写事件,对应函数是OnClose、OnReceive、OnSend。貌似CSocket触发机制封装好了,不用该语句也行。具体也理解不深,看看其他层怎么说。。。继续关注。 参考资料: 我这几天都在玩socket编程,很有意思啊! asyncSelect的作用是让socket成为异步的(非阻塞), 当指定的socket事件到达时(FD_CLOSE,FD_READ,FD_WRITE...) 对指定的window发出一个自定义的消息(WM_USER+1xx) 其中消息参数指定了事件类型便于处理。 所以如果用异步方式就不用多线程啦! 如果用多线程就用阻塞方式,因为在阻塞方式下读写是你自己控制的。 http://bbs.csdn.net/topics/23
你有没有像在他的源码基础上加多线程呢? 我下午在公司在发送端循环发送100次,发现只发了3次就断了~~
brk1985 2014-01-10
  • 打赏
  • 举报
回复
引用 84 楼 maomao85 的回复:
[quote=引用 83 楼 brk1985 的回复:] clientsocket对象添加个CString用户名 作为成员变量,用户在连接的时候发送用户名包,保存用户名,每个clientsocket对象对应一个用户名,根据用户名判断是哪个socket
up~~~ 你给我推荐了2本书???? 我怎么只看到一本???[/quote] 我只写了一本《Visual C++网络编程(含CD光盘1张)》,我也在用,感觉内容很基础,对网络编程刚刚入门的读者可以有初步提升。据说<Windows网络编程>第二版 这本也很好,买的人很多,当当上一直缺货,还没买到。另外《WinSock网络编程经络》据说也很好,这本还没怎么看。 Visual C++网络编程案例实战(配... ¥48.60 1 ¥35.40 VIP——WinSock网络编程经络 ¥32.10 1 ¥29.50 Visual C++网络编程开发与实战(配光盘) Visual C++网络编程(含CD光盘1张) 买过四本网络编程的书,也就郑阿奇的最后一本看得最多
maomao85 2014-01-10
  • 打赏
  • 举报
回复
引用 83 楼 brk1985 的回复:
clientsocket对象添加个CString用户名 作为成员变量,用户在连接的时候发送用户名包,保存用户名,每个clientsocket对象对应一个用户名,根据用户名判断是哪个socket
up~~~ 你给我推荐了2本书???? 我怎么只看到一本???
brk1985 2014-01-10
  • 打赏
  • 举报
回复
引用 80 楼 maomao85 的回复:
[quote=引用 78 楼 GLSC_CENA 的回复:] 让你比较的是容器里的元素的值,而不是容器本身,容器当然没有==这个操作了 你把元素一个个取出来做比较啊
亲,我的vector塞的是clientsocket对象啊,这个对象怎么比较的说??cstring我当然知道重载了==号操作啊[/quote] clientsocket对象添加个CString用户名 作为成员变量,用户在连接的时候发送用户名包,保存用户名,每个clientsocket对象对应一个用户名,根据用户名判断是哪个socket
这个娜戒海了 2014-01-10
  • 打赏
  • 举报
回复
引用 80 楼 maomao85 的回复:
[quote=引用 78 楼 GLSC_CENA 的回复:] 让你比较的是容器里的元素的值,而不是容器本身,容器当然没有==这个操作了 你把元素一个个取出来做比较啊
亲,我的vector塞的是clientsocket对象啊,这个对象怎么比较的说??cstring我当然知道重载了==号操作啊[/quote] 他给你推荐了两本书,建议去下载电子版的看一下
maomao85 2014-01-10
  • 打赏
  • 举报
回复
引用 76 楼 brk1985 的回复:
还在继续,加油。。。也比较关注,网络这块也比较菜鸟,公司项目也没怎么涉及网络编程。。。 郑阿奇的《Visual C++网络编程(含CD光盘1张)》第3章 即时通信:网络聊天软件 有介绍CSocket实现的版本。。。源码 论坛下载有,可以去找找。 该聊天室程序比你的版本只多了一点内容, 思路大概是在 包头结构体header添加长度、类型(用户登录或发送聊天信息)2个成员,,,连接的时候和发送聊天信息一样,同时发送2个包,一个header包、一个“用户名”包,用户名用于区分socket,,,服务器socket(CClientSocket类)的OnReceive函数(判别是登录还是发送信息,登录则接收用户名包,否则接收的是发送聊天信息)接收这个包,就可以保存该客户端的用户名。。。47楼说的标示名就是大概类似用户名的。 郑阿奇的版本,服务器端2个socket类,CServerSocket类是监听socket类、CClientSocket类是为每个客户端分配的socket类。CServerSocket类中一个客户端new一个CClientSocket类对象,并用链表存储。
亲 你是怎么自学网络编程的啊?
加载更多回复(82)

18,356

社区成员

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

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