
WindowsSOCKET编程.doc
12页Windows SOCKET编程第一章 序言我写这个专题的目的,一方面是为了通过对网络编程再一次系统的总结,提高自己的网络编程水平,特别是Windows下的网络编程水平同时,我也希望,能为众多初学网络编程的人提供一点帮助,因为我开场学习网络编程的时候,能找到的资料就很少当然,花钱可以买到翻译版本的书:〕首先向大家推荐一本很好的参考书,Network Programming for Microsoft Windows 2nd,初学网络编程的时候我还不知道有这样一本好书,只是上各大论坛把能找到的网络编程方面的文章和代码下载下来,然后自己研究后来看到别人推荐这一本书,下载了一个,看了感觉非常好,里面的容写得很规,条理也很清楚,英文好的朋友可以直接阅读,不然就只好去弄一本翻译好的来研究了我试着从Windows编程的根底开场,一直到探索建立高性能的网络应用程序我说过,我并不是以高手的身份写这本书,而是以和大家一起学习的心态学习网络编程,写书只是让自己的思路更清晰,以后还可以翻阅所以,我不保证书中所有的容都是绝对正确和标准的,有不妥的地方,还希望高手批评指正这本书是完全免费的,读者可以任意使用书中的代码。
但是如果需要,请注明原作者和出处如果有商业运作的需求,请直接和我联系第二章 Windows网络编程根底这本书主要探索Windows网络编程,开发平台是Windows 2000 和Visual C++.NET,从一个合格的C++程序员到网络编程高手,还是需要花不少功夫,至少我认为写一个聊天程序很简单,而要写一个能同时响应成千上万用户的高性能网络程序,确实不容易这篇文章所介绍的方法也并不是能直接应用于每一个具体的应用程序,只能作为学习的参考资料开发高性能网络游戏恐怕是促使很多程序员研究网络编程的原因〔包括我〕,现在的大型网络游戏对同时人数的要求比拟高,真正的工程往往采取多个效劳器〔组〕负荷分担的方式工作,我将首先把注意力放到单个效劳器的情况大家都知道,我们用得最多的协议是UDP和TCP,UDP是不可靠传输效劳,TCP是可靠传输效劳UDP就像点对点的数据传输一样,发送者把数据打包,包上有收信者的地址和其他必要信息,至于收信者能不能收到,UDP协议并不保证而TCP协议就像(实际他们是一个层次的网络协议)是建立在UDP的根底上,参加了校验和重传等复杂的机制来保证数据可靠的传到达收信者关于网络协议的具体容,读者可以参考专门介绍网络协议的书籍,或者查看RFC中的有关容。
本书直接探讨编程实现网络程序的问题2.1 Window Socket介绍Windows Socket是从UNI* Socket继承开展而来,最新的版本是2.2进展Windows网络编程,你需要在你的程序中包含WINSOCK2.H或MSWSOCK.H,同时你需要添加引入库WS2_32. LIB或WSOCK32.LIB准备好后,你就可以着手建立你的第一个网络程序了Socket编程有阻塞和非阻塞两种,在操作系统I/O实现时又有几种模型,包括Select,WSAAsyncSelect,WSAEventSelect ,IO重叠模型,完成端口等要学习根本的网络编程概念,可以选择从阻塞模式开场,而要开发真正实用的程序,就要进展非阻塞模式的编程〔很难想象一个大型效劳器采用阻塞模式进展网络通信〕在选择I/O模型时,我建议初学者可以从WSAAsyncSelect模型开场,因为它比拟简单,而且有一定的实用性但是,几乎所有人都认识到,要开发同时响应成千上万用户的网络程序,完成端口模型是最好的选择既然完成端口模型是最好的选择,那为什么我们不直接写出一个使用完成端口的程序,然后大家稍加修改就OK了我认为这确实是一个好的想法,但是真正做工程的时候,不同的情况对程序有不同的要求,如果不深入学习网络编程的各方面知识,是不可能写出符合要求的程序,在学习网络编程以前,我建议读者先学习一下网络协议。
2.2 第一个网络程序由于效劳器/客户端模式的网络应用比拟多,而且效劳器端的设计是重点和难点所以我想首先探讨效劳器的设计方法,在完成效劳器的设计后再探讨其他模式的网络程序设计一个根本的网络效劳器有以下几个步骤:1、初始化Windows Socket2、创立一个监听的Socket3、设置效劳器地址信息,并将监听端口绑定到这个地址上4、开场监听5、承受客户端连接6、和客户端通信7、完毕效劳并清理Windows Socket和相关数据,或者返回第4步我们可以看出设计一个最简单的效劳器并不需要太多的代码,它完全可以做一个小型的聊天程序,或进展数据的传输但是这只是我们的开场,我们的最终目的是建立一个有大规模响应能力的网络效劳器如果读者对操作系统局部的线程使用还有疑问,我建议你现在就开场复习,因为我们经常使用线程来提高程序性能,其实线程就是让CPU不停的工作,而不是总在等待I/O,或者是一个CPI,累死了还是一个CPU千万不要以为线程越多的效劳器,它的性能就越好,线程的切换也是需要消耗时间的,对于I/O等待少的程序,线程越多性能反而越低下面是简单的效劳器和客户端源代码〔阻塞模式下的,供初学者理解〕TCPServer#include <winsock2.h>void main(void){WSADATA wsaData;SOCKET ListeningSocket;SOCKET NewConnection;SOCKADDR_IN ServerAddr;SOCKADDR_IN ClientAddr;int Port = 5150;// 初始化Windows Socket 2.2WSAStartup(MAKEWORD(2,2), &wsaData);// 创立一个新的Socket来响应客户端的连接请求ListeningSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);// 填写效劳器地址信息// 端口为5150// IP地址为INADDR_ANY,注意使用htonl将IP地址转换为网络格式ServerAddr.sin_family = AF_INET;ServerAddr.sin_port = htons(Port); ServerAddr.sin_addr.s_addr = htonl(INADDR_ANY);// 绑定监听端口bind(ListeningSocket, (SOCKADDR *)&ServerAddr, sizeof(ServerAddr));// 开场监听,指定最时连接数为5listen(ListeningSocket, 5); // 承受新的连接NewConnection = accept(ListeningSocket, (SOCKADDR *) &ClientAddr,&ClientAddrLen));// 新的连接建立后,就可以互相通信了,在这个简单的例子中,我们直接关闭连接,// 并关闭监听Socket,然后退出应用程序// closesocket(NewConnection);closesocket(ListeningSocket);// 释放Windows Socket DLL的相关资源WSACleanup();}TCPClient# include <winsock2.h>void main(void){WSADATA wsaData;SOCKET s;SOCKADDR_IN ServerAddr;int Port = 5150;//初始化Windows Socket 2.2WSAStartup(MAKEWORD(2,2), &wsaData);// 创立一个新的Socket来连接效劳器s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);// 填写客户端地址信息// 端口为5150// 效劳器IP地址为"136.149.3.29",注意使用inet_addr将IP地址转换为网络格式ServerAddr.sin_family = AF_INET;ServerAddr.sin_port = htons(Port); ServerAddr.sin_addr.s_addr = inet_addr("136.149.3.29");// 向效劳器发出连接请求connect(s, (SOCKADDR *) &ServerAddr, sizeof(ServerAddr)); // 新的连接建立后,就可以互相通信了,在这个简单的例子中,我们直接关闭连接,// 并关闭监听Socket,然后退出应用程序closesocket(s);// 释放Windows Socket DLL的相关资源WSACleanup();}2.3 WSAAsyncSelect模式前面说过,Windows网络编程模式有好几种,他们各有特点,实现起来复杂程度各不一样,适用围也不一样。
下列图是Network Programming for Microsoft Windows 2nd 一书中对不同模式的一个性能测试结果效劳器采用Pentium 4 1.7 GHz *eon的CPU,768M存;客户端有3台PC,配置分别是Pentium 2 233MHz ,128 MB 存,Pentium 2 350 MHz ,128 MB存,Itanium 733 MHz ,1 GB存具体的结果分析大家可以看看原书中作者的表达,我关心的是哪种模式是我需要的首先是效劳器,勿庸置疑,肯定是完成端口模式则客户端呢,当然也可以采用完成端口,但是不同模式是在不同的操作系统下支持的,看下列图:完成端口在Windows 98下是不支持的,虽然我们可以假定所有的用户都已经装上了Windows 2000和Windows *P,但是,如果是商业程序,这种想法在现阶段不应该有,我们不能让用户为了使用我们的客户端而去升级他的操作系统Overlapped I/O可以在Windows 98下实现,性能也不错,但是实现和理解起来快赶上完成端口了而且,最关键的一点,客户端程序不是用来进展大规模网络响应的,客户端的主要工作应该是进展诸如图形运算等非网络方面的任务。
原书作者,包括我强烈推荐大家使用WSAAsyncSelect模式实现客户端,因为它实现起来比拟直接和容易,而且他完全可以满足客户端编程的需求下面是一段源代码,虽然我们是用它来写客户端,我还是把它的效劳端代码放上来,一方面是有兴趣的朋友可以用他做测试和了解如何用它实现效劳器;另一方面是客户端的代码可以很容易的从它修改而成,不同的地方只要参考一下2.1节里的代码就知道了define WM_SOCKET WM_USER + 1#include <winsock2.h>#include <windows.h>int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine,int nCmdShow){WSADATA wsd;SOCKET Listen;SOCKADDR_IN InternetAddr;HWND Window;// 创立主窗口Window = CreateWindow();// 初始化Windows Socket 2.2WSAStartup(MAKEW。












