200分,C++网络通信,高手,工作过的进!!

我正在搞C++网络通信编程这个模块,以下的问题不是非常的明白请大家不惜赐教,就这两百分了!!第一我假设一个服务端应用程序ServerDlg(简称A),一个客户端应用程序C... 我正在搞C++网络通信编程这个模块,以下的问题不是非常的明白请大家不惜赐教,就这两百分了!!

第一 我假设一个服务端应用程序ServerDlg(简称A),一个客户端应用程序CliengDlg(简称B),现在我我在A中定义一个CSock类m,m在初始化函数中创建,监听,在B中创建一个CSocket

类n并且在初始化函数中创建,并连接到A,现在问题是A中应该在什么地方调用Accept()?可以不创建线程来Accept(),而直接在它的其他成员函数中Accept()吗?
第二,就算服务端Accept()成功,以后接受与发送数据是不是只有通过线程进行?接受,发送数据的代码可以写在Dlg的成员函数中吗?我没通过继承CSocket来实现,所以不能OnReceive(

)和OnSend()来实现通信?
第三,如果我把它换成异步CAsynSocket,那么上面感觉行不通了?怎样用到异步CAsynSocket?
第四,如果我把上面两个CSocket换成CAsynSocket,怎样才能使两个不同应用程序的对话框他们实现通信?关键是阻塞与非阻塞我不能灵活运用?(注意,我不是通过继承,而是维护

CSocket对象实现通信,这样做可以嘛??
展开
 我来答
wykljklc
2010-06-18
知道答主
回答量:1
采纳率:0%
帮助的人:0
展开全部
朋友!!!我感觉应该如下
CSocket是MFC在CAsyncSocket基础上派生的一个同步阻塞Socket的封装类。它是如何又把CAsyncSocket变成同步的,而且还能响应同样的Socket事件呢? 其实很简单,CSocket在Connect()返回WSAEWOULDBLOCK错误时,不是在OnConnect(),OnReceive()这些事件终端函数里去等待。你先必须明白Socket事件是如何到达这些事件函数里的。这些事件处理函数是CSocketWnd窗口对象回调的,而窗口对象收到来自Socket的事件,又是靠线程消息队列分发过来的。总之,Socket事件首先是作为一个消息发给CSocketWnd窗口对象,这个消息肯定需要经过线程消息队列的分发,最终CSocketWnd窗口对象收到这些消息就调用相应的回调函数(OnConnect()等)。 所以,CSocket在调用Connect()之后,如果返回一个WSAEWOULDBLOCK错误时,它马上调用一个用于提取消息的函数PumpMessage(...),就是从当前线程的消息队列里取关心的消息. PumnMessage会遇到下面几种情况: 1 提取出了(从消息队列中移出来Remove),用户正在使用的一个Socket发送的WM_SOCKET_NOTIFY消息和对应的 FD_XXX事件,返回True. 2 提取出了(从消息队列中移出来Remove),用户正在使用的一个Socket发送的WM_SOCKET_NOTIFY消息和对应的 FD_Close事件,返回True. 3 提取出了(从消息队列中移出来Remove),PumpMessage(..)设定的定时器的WM_TIMER消息,TimeOut事件为 CSocket的一个成员变量,m_nTimeOut=2000ms,返回True 4 用户调用了CancelBlockingCall() 设置错误代码为WSAEINTR(被中断了),返回False 5 用户一直没有取到用户正在使用的一个Socket发送的WM_SOCKET_NOTIFY消息和对应的FD_XXX事件,但是取到 了同一个线程中的其他Socket的WM_SOCKET_NOTIFY消息及其对应的消息,则将这些消息,加入到一个辅助性 的队列中去,以后处理. 6 没有取到任何WM_SOCKET_NOTIFY消息,则开始查看(不是取出来,而是查看)本线程的消息队列中是否有其他 消息,如果有的话,调用虚函数OnMessagePending(),来处理这些消息(OnMessagePending()用户可以自定义 在阻塞时,用户想要处理的消息),如果没有,则调用WaitMessage()开始等待消息的到来. 代码说明如下: A 先看Connect,因为Connect的阻塞的实现和Accept,Receive,ReceiveFrom,Send,SendTo都有点不同. 也许你们会奇怪为何是ConnectHelper(...),而不是Connect(...).其实ConnectHelper(...)才是Connect(..) 真正调用的东西,如下: BOOL CAsyncSocket::Connect(const SOCKADDR* lpSockAddr, int nSockAddrLen) { return ConnectHelper(lpSockAddr, nSockAddrLen); } //ConnectHelper( ... )为一虚函数 //继承自CAsyncSocket,Csocket有重新定义过. //这也是为什么CSocket是Public继承的原因 BOOL CSocket::ConnectHelper( ... ) { //一旦调用 就先检查当前是否有一个阻塞操作正在进行 //如果是,立马返回,并设置错误代码. ...... ...... m_nConnectError = -1; //注意它只调用了一次CAsyncSocket::ConnectHelper( ... ) if( !CAsyncSocket::ConnectHelper( ... ) ) { //由于Connect(...)要求自己和Server进行三步握手 //即需要发送一个Packet,而且等待回复(这个也就是 //涉及连接和发送数据操作的Socket API会阻塞的原因) //所以CAsyncSocket::ConnectHelper(...)会立即返回, //并且设置错误为WSAEWOULDBLOCK(调用该函数会导致阻塞) if( WSAGetLastError() == WSAEWOULDBLOCK ) { //进入消息循环,以从线程消息队列里查看FD_CONNECT消息, //收到FD_CONNECT消息(在PumpMessage中会修改m_nConnectError),返回 //或者WM_TIMER/FD_CLOSE(return true,但不会修改m_nConnectError), //继续调用PumpMessage来取消息 //或者错误,那么就返回socket_error while( PumpMessages( FD_CONNECT ) ) { if (m_nConnectError != -1) { WSASetLastError(m_nConnectError); return (m_nConnectError == 0); } } //end while } return false; } return true; } //在PumpMessages中会设置一个定时器,时间为m_nTimeOut=2000ms //当在这个时间之内,依然没有得到消息的话,就返回 BOOL CSocket::PumpMessages( UINT uStopFlag ) { //一旦进入这个函数,就设置Socket当前状态为阻塞 BOOL bBlocking = TRUE; m_pbBlocking = &bBlocking; .................... ..................... .................... CWinThread* pThread = AfxGetThread(); //bBlocking是一个标志, // 用来判断用户是否取消对Connect()的调用 //即是否调用CancelBlockingCall() while( bBlocking ) { //#define WM_SOCKET_NOTIFY 0x0373 //#define WM_SOCKET_DEAD 0x0374 MSG msg; //在此处只是取WM_SOCKET_NOTIFY 和 WM_SOCKET_DEAD消息 if (::PeekMessage(&msg, pState->m_hSocketWindow,WM_SOCKET_NOTIFY, WM_SOCKET_DEAD, PM_REMOVE)) { if (msg.message == WM_SOCKET_NOTIFY && (SOCKET)msg.wParam == m_hSocket) { //这个是PumpMessage的第2种情况 if (WSAGETSELECTEVENT(msg.lParam) == FD_CLOSE) { break;} //这个是PumpMessage的第1种情况 if(WSAGETSELECTEVENT(msg.lParam) == uStopFlag ) { ......; break;} } //这个是PumpMessage的第5种情况 if (msg.wParam != 0 || msg.lParam != 0) CSocket::AuxQueueAdd(msg.message, msg.wParam, msg.lParam); } //这个是PumpMessage的第3种情况 else if (::PeekMessage(&msg, pState->m_hSocketWindow,WM_TIMER, WM_TIMER, PM_REMOVE)) { break;} //这个是PumpMessage的第6种情况 if (bPeek && ::PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) { if (OnMessagePending()) { } else { WaitMessage(); ..... } } }//end while ////这个是PumpMessage的第4种情况 if (!bBlocking) { WSASetLastError(WSAEINTR); return FALSE; } m_pbBlocking = NULL; //将WM_SOCKET_NOTIFY消息发送到Creat CSocketWnd线程的消息队列中 //以便处理其他的Socket消息 ::PostMessage(pState->m_hSocketWindow, WM_SOCKET_NOTIFY, 0, 0); return TRUE; } B 再看Receive(..) //其实CSocket的这种实现方式决定了,应用程序不能够在一个线程中Create一个socket, //然后创建一个新的线程来专门Receive,因为这个新的线程将永远不能取到FD_Read的事件, //因为并不是在这个线程中创建的CSocketWnd对象,它无法接受到发送到CSocketWnd的消息 //(在Windows中接受消息的主体是窗口) //Receive和Connect的实现方式的最大区别为 //Connect 是不断的调用PumpMessage(..) //而Receive则不断的调用自身 int CSocket::Receive(void* lpBuf, int nBufLen, int nFlags) { if (m_pbBlocking != NULL) { WSASetLastError(WSAEINPROGRESS); return FALSE; } int nResult; while ((nResult = CAsyncSocket::Receive(lpBuf, nBufLen, nFlags)) == SOCKET_ERROR) { if (GetLastError() == WSAEWOULDBLOCK) { //一旦提取到FD_READ///FD_CLOSE///WM_TIMER时 // 就再次调用CAsyncSocket::Receive(...) if (!PumpMessages(FD_READ)) return SOCKET_ERROR; } else return SOCKET_ERROR; } return nResult; } 最后,总结一下自己对CSocket的看法, 1 虽然它解决了结束阻塞线程的方法,调用CancelBlockingCall,但是多线程模式根本就不适合于CSocket 2 CSocket和CAsyncSocket利用Windows的消息模式将前台的界面处理和后台的网络通信都整合到消息传递模型 下,但是很明显,一旦后台的网络过于繁忙,则前台的处理可能就无法顾及,所以CSocket也就只能小打小闹
建议你多看MSDN,上面说的清楚,和孙鑫的VC++视频!!
高骏(北京)科技有限公司
2020-04-29 广告
多链路4G传输建议选择高骏(北京)科技有限公司,价格合理,品质高服务好。高骏(北京)科技有限公司简称高骏科技。Cogent(高骏科技)创立于 2011年,始终致力于核心技术和创新性产品的自主研发,目前已成为国际知名的无线视音频传输与通信产品... 点击进入详情页
本回答由高骏(北京)科技有限公司提供
百度网友d684ebaa0
2010-06-16
知道答主
回答量:5
采纳率:0%
帮助的人:0
展开全部
来学习下 以后也是这方面的工人了
已赞过 已踩过<
你对这个回答的评价是?
评论 收起
软式曲奇饼
2010-06-16 · 超过25用户采纳过TA的回答
知道答主
回答量:40
采纳率:0%
帮助的人:70.7万
展开全部
MFC下面的两个SOCKET是基于SOCKET的异步选择模型,该模型通过WINDOWS的消息

机制完成事件的通知机制,该模型需要你提供一个窗体来完成对注册的网络事件

的响应。由于MFC中已经将这个窗体的操作实现了,所以程序员不需要在去做类

似的工作,需要做的是通过继承并重写CAsynSocket提供的虚函数

(如virtual void OnAccept( int nErrorCode )), 从而接收来自网络的消

息。

综上所述、关于问题:

第一,可以在单线程中操作CAsynSocket, CSocket. 但是不继承这两个类是不行

的,因为这两个提供的唯一的接口就是他自己本身的虚函数,也就是说他们即是

实现类,也是接口类。

A中需要家一个类继承CSocket 响应virtual void OnAccept( int

nErrorCode ); 在里面调用Accept()。

第二,同上、不需要单开辟线程,但是需要一个继承类,至少要响应

CAsyncSocket::OnReceive 才能知道什么时候会有网络数据来。

第三,CAsynSocket只是操作异步化了,响应方式没有变化,因为CSocket就是从

CAsynSocket继承来的。

第四,SOCKET通信,你需要做的就是了解I/O的模型,然后组织自己的应用协

议,管理内存。

CSocket提供了阻塞调用,但不是最关键的,关键是他提供了基于序列对象的

功能。

如果还有疑问, 可以再联系我。 我一直在做网络服务器程序的开发。如果你希

望开发出高并发的服务器程序,我们也可以切磋一下。
已赞过 已踩过<
你对这个回答的评价是?
评论 收起
weilin928
2010-06-16 · TA获得超过110个赞
知道答主
回答量:137
采纳率:0%
帮助的人:144万
展开全部
- -!

楼主是初学者吧?
建议你去看看孙鑫的视频教程 然后我相信你就不会问这个问题了
已赞过 已踩过<
你对这个回答的评价是?
评论 收起
dr_zxp
2010-06-17 · TA获得超过861个赞
知道小有建树答主
回答量:765
采纳率:100%
帮助的人:856万
展开全部
windwos下是现成的,你需要做的就是两头,数据组织和加工
已赞过 已踩过<
你对这个回答的评价是?
评论 收起
小止学编程
2010-06-17 · TA获得超过133个赞
知道答主
回答量:74
采纳率:0%
帮助的人:89.5万
展开全部
如果你不想继承的话,建议你直接使用Socket API。
使用函数int WSAAsyncSelect(
__in SOCKET s,
__in HWND hWnd,
__in unsigned int wMsg,
__in long lEvent
);

将socket和窗口句柄绑定起来,lEvent里选择FD_READ、FD_WRITE、FD_ACCEPT、FD_CONNECT和FD_CLOSE等等你所希望处理的事件。
这样当事件发生是,系统会向你的窗口发送WM_SOCKET消息。
你可以重载WinProc函数来检查WM_SOCKET消息。
具体可以参考《WINDOWS网络编程技术》第8章
已赞过 已踩过<
你对这个回答的评价是?
评论 收起
收起 更多回答(4)
推荐律师服务: 若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询

为你推荐:

下载百度知道APP,抢鲜体验
使用百度知道APP,立即抢鲜体验。你的手机镜头里或许有别人想知道的答案。
扫描二维码下载
×

类别

我们会通过消息、邮箱等方式尽快将举报结果通知您。

说明

0/200

提交
取消

辅 助

模 式