《winsock编程》由会员分享,可在线阅读,更多相关《winsock编程(23页珍藏版)》请在金锄头文库上搜索。
1、socket 编程基础socket 是什么意思在计算机通信领域,socket 被翻译为“套接字” ,它是计算机之间进行通信的一种约定或一种方式。通过 socket 这种约定,一台计算机可以接收其他计算机的数据,也可以向其他计算机发送数据。socket 的典型应用就是 Web 服务器和浏览器:浏览器获取用户输入的 URL,向服务器发起请求,服务器分析接收到的 URL,将对应的网页内容返回给浏览器,浏览器再经过解析和渲染,就将文字、图片、视频等元素呈现给用户。一个简单的 Windows 下的 socket 程序服务器端代码 server.cpp: #include 2. #include 3. #
2、pragma comment (lib, ws2_32.lib) /加载 ws2_32.dll4.5. int main()6. /初始化 DLL7. WSADATA wsaData;8. WSAStartup( MAKEWORD(2, 2), 9.10. /创建套接字11. SOCKET servSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);12.13. /绑定套接字14. sockaddr_in sockAddr;15. memset( /每个字节都用 0 填充16. sockAddr.sin_family = PF_INET; /使用
3、IPv4 地址17. sockAddr.sin_addr.s_addr = inet_addr(127.0.0.1); /具体的 IP 地址18. sockAddr.sin_port = htons(1234); /端口19. bind(servSock, (SOCKADDR*)20.21. /进入监听状态22. listen(servSock, 20);23.24. /接收客户端请求25. SOCKADDR clntAddr;26. int nSize = sizeof(SOCKADDR);27. SOCKET clntSock = accept(servSock, (SOCKADDR*)2
4、8.29. /向客户端发送数据30. char *str = Hello World!;31. send(clntSock, str, strlen(str)+sizeof(char), NULL);32.33. /关闭套接字34. closesocket(clntSock);35. closesocket(servSock);36.37. /终止 DLL 的使用38. WSACleanup();39.40. return 0;41. 客户端代码 client.cpp: #include 2. #include 3. #include 4. #pragma comment(lib, ws2_3
5、2.lib) /加载 ws2_32.dll5.6. int main()7. /初始化 DLL8. WSADATA wsaData;9. WSAStartup(MAKEWORD(2, 2), 10.11. /创建套接字12. SOCKET sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);13.14. /向服务器发起请求15. sockaddr_in sockAddr;16. memset( /每个字节都用 0 填充17. sockAddr.sin_family = PF_INET;18. sockAddr.sin_addr.s_addr = i
6、net_addr(127.0.0.1);19. sockAddr.sin_port = htons(1234);20. connect(sock, (SOCKADDR*)21.22. /接收服务器传回的数据23. char szBufferMAXBYTE = 0;24. recv(sock, szBuffer, MAXBYTE, NULL);25.26. /输出接收到的数据27. printf(Message form server: %sn, szBuffer);28.29. /关闭套接字30. closesocket(sock);31.32. /终止使用 DLL33. WSACleanup
7、();34.35. system(pause);36. return 0;37. 将 server.cpp 和 client.cpp 分别编译为 server.exe 和 client.exe,先运行 server.exe,再运行 client.exe,输出结果为:Message form server: Hello World!注意:1) Windows 下的 socket 程序依赖 Winsock.dll 或 ws2_32.dll,必须提前加载。DLL 有两种加载方式。2) Windows 使用 “文件句柄”的概念; Windows 下为 SOCKET 类型,也就是句柄。3) Window
8、s 下使用 recv() / send() 函数发送和接收。4) Windows 使用 closesocket() 函数。WSAStartup()函数以及 DLL 的加载WinSock(Windows Socket)编程依赖于系统提供的动态链接库(DLL),有两个版本: 较早的 DLL 是 wsock32.dll,大小为 28KB,对应的头文件为 winsock1.h; 最新的 DLL 是 ws2_32.dll,大小为 69KB,对应的头文件为 winsock2.h。几乎所有的 Windows 操作系统都已经支持 ws2_32.dll,包括个人操作系统 Windows 95 OSR2、Wind
9、ows 98、 Windows Me、Windows 2000、XP、Vista、Win7、Win8、Win10 以及服务器操作系统 Windows NT 4.0 SP4、 Windows Server 2003、Windows Server 2008 等,所以你可以毫不犹豫地使用最新的 ws2_32.dll。使用 DLL 之前必须把 DLL 加载到当前程序,你可以在编译时加载,也可以在程序运行时加载。这里使用#pragma 命令,在编译时加载: #pragma comment (lib, ws2_32.lib)WSAStartup() 函数使用 DLL 之前,还需要调用 WSAStartup
10、() 函数进行初始化,以指明 WinSock 规范的版本,它的原型为: int WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData);wVersionRequested 为 WinSock 规范的版本号,低字节为主版本号,高字节为副版本号(修正版本号) ;lpWSAData 为指向 WSAData 结构体的指针。关于 WSAData 结构体WSAStartup() 函数执行成功后,会将与 ws2_32.dll 有关的信息写入 WSAData 结构体变量。WSAData 的定义如下:1. typedef struct WSAData 2.
11、 WORD wVersion; /ws2_32.dll 建议我们使用的版本号3. WORD wHighVersion; /ws2_32.dll 支持的最高版本号4. /一个以 null 结尾的字符串,用来说明 ws2_32.dll 的实现以及厂商信息5. char szDescriptionWSADESCRIPTION_LEN+1;6. /一个以 null 结尾的字符串,用来说明 ws2_32.dll 的状态以及配置信息7. char szSystemStatusWSASYS_STATUS_LEN+1;8. unsigned short iMaxSockets; /2.0 以后不再使用9. u
12、nsigned short iMaxUdpDg; /2.0 以后不再使用10. char FAR *lpVendorInfo; /2.0 以后不再使用11. WSADATA, *LPWSADATA;最后 3 个成员已弃之不用,szDescription 和 szSystemStatus 包含的信息基本没有实用价值,读者只需关注前两个成员即可。综上所述:WinSock 编程的第一步就是加载 ws2_32.dll,然后调用 WSAStartup() 函数进行初始化,并指明要使用的版本号。在 Windows 下创建 socketWindows 下也使用 socket() 函数来创建套接字,原型为:
13、SOCKET socket(int af, int type, int protocol);除了返回值类型不同,其他都是相同的。Windows 不把套接字作为普通文件对待,而是返回 SOCKET 类型的句柄。请看下面的例子: SOCKET sock = socket(AF_INET, SOCK_STREAM, 0); /创建 TCP 套接字使用 bind()和 connect()函数socket() 函数用来创建套接字,确定套接字的各种属性,然后服务器端要用 bind() 函数将套接字与特定的 IP 地址和端口绑定起来,只有这样,流经该 IP 地址和端口的数据才能交给套接字处理;而客户端要用
14、connect() 函数建立连接。 bind() 函数bind() 函数的原型为: int bind(int sock, struct sockaddr *addr, socklen_t addrlen); /Linuxint bind(SOCKET sock, const struct sockaddr *addr, int addrlen); /Windows下面以 Linux 为例进行讲解,Windows 与此类似。sock 为 socket 文件描述符,addr 为 sockaddr 结构体变量的指针,addrlen 为 addr 变量的大小,可由 sizeof() 计算得出。下面的代
15、码,将创建的套接字与 IP 地址 127.0.0.1、端口 1234 绑定: /创建套接字2. int serv_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);3.4. /创建 sockaddr_in 结构体变量5. struct sockaddr_in serv_addr;6. memset( /每个字节都用 0 填充7. serv_addr.sin_family = AF_INET; /使用 IPv4 地址8. serv_addr.sin_addr.s_addr = inet_addr(127.0.0.1); /具体的 IP 地址9. serv_addr.sin_port = htons(1234); /端口10.11. /将套接字和 IP、端口绑定12. bind(serv_sock, (struct socka