资源预览内容
第1页 / 共7页
第2页 / 共7页
第3页 / 共7页
第4页 / 共7页
第5页 / 共7页
第6页 / 共7页
第7页 / 共7页
亲,该文档总共7页全部预览完了,如果喜欢就下载吧!
资源描述
VC+下实现下实现 Socket 编程方法编程方法利用 Socket 编程是一类典型的网络通信程序,特别是在实时性要求比较 高的项目中,Winsock 编程方法是非常实用的。下面介绍在 VC 6.0 环境下开 发 Winsock 程序的方法。 这里并没有直接应用 MFC 提供的 CSocket 类,这是因为考虑到对于类而言, 其成员函数调用必然是完全阻塞方式的,因此只能用于人工线程中。基于这 种思想,可以在 CObject 类基础上派生一个套接字类,其使用方式为阻塞方 式,虽然增加了使用的条件,但可以保证其正常工作,而不会出现不加控制 地使用 CSocket 对象带来的冲突现象。 下面首先将具体介绍有关的套接字类的定义,新创建的套接字功能主要通 过调用 CSocket 的相关操作实现。 1 1 套接字类套接字类 CBlockingSocketCBlockingSocket 首先需要定义此套接字类,在类中设置了一个属性变量:SOCKET m_hSocket; m_hSocket 表示套接字的句柄。另外还构造了一组方法,其功 能与 CSocket 类是对应的,下面以创建、监听、连接建立和消息的接收和发 送为例,介绍其实现方法,。 创建 创建套接字即要求创建相应的连接,缺省类型为面向连接的流,具体实现 为: void CBlockingSocket:Create(int nType) ASSERT(m_hSocket = NULL); if(m_hSocket = socket(AF_INET, nType, 0) = INVALID_SOCKET) throw new CBlockingSocketException(“创建套接字“); 监听 Listen 函数完成监听连接的任务,在实现时要求最多有 10 个连接请求排 队,这在一般的应用中是完全足够的。 void CBlockingSocket:Listen() ASSERT(m_hSocket != NULL); if(listen(m_hSocket, 10) = SOCKET_ERROR) throw new CBlockingSocketException(“Listen“); 建立连接 连接的实际建立可以由 Connect 实现,同样地,缺省的建立方式为面向连 接的流。 void CBlockingSocket:Create(int nType ) ASSERT(m_hSocket = NULL); if(m_hSocket = socket(AF_INET, nType, 0) = INVALID_SOCKET) throw new CBlockingSocketException(“创建套接字“); 发送消息 Send 函数的作用是将数据块按一个消息发送,参数 pch 即为发送的消息,nSize 为消息长度,nSecs 可以限制操作时间。如果客户方取消读操作,则返 回值将小于指定消息长度。 int CBlockingSocket:Send(const char* pch, const int nSize, const int nSecs) ASSERT(m_hSocket != NULL); FD_SET fd = 1, m_hSocket; TIMEVAL tv = nSecs, 0; if(select(0, NULL, if(int nBytesSent = send(m_hSocket, pch, nSize, 0) = SOCKET_ERROR) throw new CBlockingSocketException(“发送“); return nBytesSent; 此外,如果数据块比较大,可以将数据块分成多个消息发送,此工作由函 数 Write 完成。具体实现时将通过循环调用 Send 函数来实现部分消息发送, 通过对局部量 nBytesThisTime 和 nBytesSent 的维护,保证整个数据块的正 常发送。 int CBlockingSocket:Write(const char* pch, const int nSize, const int nSecs) int nBytesSent = 0,nBytesThisTime; const char* pch1 = pch; do nBytesThisTime = Send(pch1, nSize - nBytesSent, nSecs); nBytesSent += nBytesThisTime; pch1 += nBytesThisTime; while(nBytesSent Delete(); 下面,再来看线程函数 ServerThreadProc 是如何处理客户请求的: UINT ServerThreadProc(LPVOID pParam) CSockAddr saClient; CBlockingSocket sConnect; try if(!g_sListen.Accept(sConnect, saClient) g_bListening = FALSE; return 0; g_nConnection+; AfxBeginThread(ServerThreadProc, pParam, THREAD_PRIORITY_NORMAL); DoRequest(pParam, sConnect, saClient); sConnect.Close(); / 析构函数不能关闭它 catch(CBlockingSocketException* pe) LogBlockingSocketException(pParam, “服务器:“, pe); pe-Delete(); return 0; 如果 g_sListen 调用 Accept 失败,说明视或应用程序关闭了连接的套接 字,此时将调整当前状态,在具体处理客户请求之前,为了不影响继续接收 其它客户的请求,可以再创建新的线程,即构造多线程,每个线程处理自已 的具体事务。具体处理工作由 DoRequest 函数完成,由于析构函数不能关闭 临时建立的套接字,所以在处理完之后,需要主动关闭。DoRequest 的工作包括在服务器应用视中显示相应的提示语句,这是通过 向其发送消息完成的,另外还将显示客户发送的信息,信息由套接字的 Receive()函数获得,同样通过向窗口发送消息完成,这里的消息发送窗口 由参数 pParam 确定。最后,调用套接字的.Send()函数向客户端发送一条简 短的确认信息。 void DoRequest(LPVOID pParam, CBlockingSocket wsprintf(text1, “建立连接rn“); :SendMessage(HWND) pParam, EM_SETSEL, (WPARAM) 500, 65535); :SendMessage(HWND) pParam, EM_REPLACESEL, (WPARAM) 0, (LPARAM) text1);try int len=sockCon.Receive(inbuff,500,20); inbufflen=0; :SendMessage(HWND) pParam, EM_SETSEL, (WPARAM) 500, 65535);:SendMessage(HWND)pParam,EM_REPLACESEL,(WPARAM)0,(LPARAM)inbuff); sockCon.Send(“ok!rnBye!“,9,5); catch(CBlockingSocketException* pe) LogBlockingSocketException(pParam, “服务器:“, pe); pe-Delete(); 5 5 客户端应用程序客户端应用程序 在客户端应用程序中同样使用了前面介绍的套接字类 CBlockingSocket,Winsock 地址类 CSockAddr 和套接字异常类 CBlockingSocketException。 这里将主要介绍客户如何建立与服务器的连接,如何向服务器发送消息, 以及如何接收和处理服务器返回的消息。 为了实现与服务器的连接,需要在菜单上增加一个连接项,资源标识为 ID_BEGIN_LINK,消息映射设置为 ON_COMMAND(ID_BEGIN_LINK, OnBeginLink), 下面再来分析消息处理函数 OnBeginLink 的实现: void CTestclientsockView:OnBeginLink() CBlockingSocket sClient; char inbuff200; try CSockAddr saClient(“146.127.35.70“,5858); sClient.Create(); sClient.Connect(saClient); sClient.Send(“hello ,你好!n“,5,5); int len=sClient.Receive(inbuff,200,20); inbufflen=0;SendMessage(EM_SETSEL, (WPARAM) 500, 65535); SendMessage(EM_REPLACESEL, (WPARAM) 0, (LPARAM) inbuff); sClient.Close(); catch(CBlockingSocketException* e) sClient.Cleanup(); LogBlockingSocketException(GetSafeHwnd(), “VIEW:“, e); e-Delete(); 首先需要建立与服务器的连接,这里创建了一个地址对象 saClient,在创 建时提供了两个参数,其中“146.127.35.70”为服务器的 IP 地址,另外将 端口号设置为 5858,即与服务器应用程序保持一致。接下来创建一个客户端 的套接字对象,并通过调用函数 Connect 建立与服务器的连接。连接建立后, 可以向服务器发送信息了,这里用套接字的函数 Send()发送了一条简短的欢 迎信息,同时调用 Receive()函数接收服务器返回的信息。最后向视发送显 示消息,将服务器所返回的确认信息显示在主窗口中。 这里还需要说明的是,如果在连接或通信过程中出现异常,无论是客户应 用程序还是服务器应用程序都将做出相应的响应。具体的处理工作由函数 LogBlockingSocketException 实现,这里的参数 pParam 为拥有目的窗口的 HWND ,这是由另一个线程提供的。 void LogBlockingSocketException(LPVOID pParam, char* pch, CBlockingSocketException* pe) CString strGmt = CTime:GetCurrentTime().FormatGmt(“%m/%d/%y %H:%M:%S GMT“); char text1200, text250; pe-GetErrorMessage(text2, 49); wsprintf(text1, “WINSOCK 错误-%s %s - %srn“, pch, text2, (const char*) strGmt); :SendMessage(HWND) pParam, EM_SETSEL, (WPARAM) 65534, 65535); :SendMessa
网站客服QQ:2055934822
金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号