版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、第第5章章 Socket编程基础编程基础在开发网络应用程序在开发网络应用程序时,最重要的问题就时,最重要的问题就是如何实现不同主机是如何实现不同主机之间的通信。在之间的通信。在TCP/IPTCP/IP网络环境中,网络环境中,可以使用可以使用SocketSocket接口接口来建立网络连接、实来建立网络连接、实现主机之间的数据传现主机之间的数据传输。本章将介绍使用输。本章将介绍使用SocketSocket接口来编写网接口来编写网络应用程序的基本方络应用程序的基本方法。法。本章知识点本章知识点pSocketSocket协议原理协议原理pWinSockWinSock编程基础编程基础p面向连接的面向连接
2、的SocketSocket编程编程p面向非连接的面向非连接的SocketSocket编程编程p套接字选项套接字选项5.1 Socket协议原理协议原理5.1.1 Socket5.1.1 Socket协议的工作原理协议的工作原理5.1.2 Socket5.1.2 Socket的服务方式和类型的服务方式和类型5.1.1 Socket协议的工作原理协议的工作原理在网络应用程序中,实现网络通信在网络应用程序中,实现网络通信的必要条件的必要条件:(1)拨打电话的一方需要知道对方的电话号码。如果对方使用的是)拨打电话的一方需要知道对方的电话号码。如果对方使用的是内部电话,则还需要知道分机号码。而被拨打的电
3、话则不需要知道对内部电话,则还需要知道分机号码。而被拨打的电话则不需要知道对方的号码。方的号码。(2)被拨打的电话号码必须已经启用,而且将电话线连接到电话机)被拨打的电话号码必须已经启用,而且将电话线连接到电话机上。上。(3)被拨打电话的主人有空闲时间可以接听电话,如果长期无人接)被拨打电话的主人有空闲时间可以接听电话,如果长期无人接听,则会自动挂断电话。听,则会自动挂断电话。(4)双方必须使用相同的语言进行通话。这一条看似有些多余,但)双方必须使用相同的语言进行通话。这一条看似有些多余,但如果真的一个说汉语、另一个却说英语,那也是没有办法正常沟通的。如果真的一个说汉语、另一个却说英语,那也是
4、没有办法正常沟通的。(5)在通话过程中,物理线路必须保持通畅,否则电话将会被挂断。)在通话过程中,物理线路必须保持通畅,否则电话将会被挂断。(6)在通话过程中,任何一方都可以主动挂断电话。)在通话过程中,任何一方都可以主动挂断电话。基于基于TCP协议的两个网络应用程序进行通信的基本过程协议的两个网络应用程序进行通信的基本过程 (1)客户端(相当于拨打电话的一方)需要了解服务器的地址(相当于电话号码)。)客户端(相当于拨打电话的一方)需要了解服务器的地址(相当于电话号码)。在在TCP/IP网络环境中,可以使用网络环境中,可以使用IP地址来标识一个主机。但仅仅使用地址来标识一个主机。但仅仅使用IP
5、地址是不够的,地址是不够的,如果一台主机中运行了多个网络应用程序,那么如何确定与哪个应用程序通信呢。在如果一台主机中运行了多个网络应用程序,那么如何确定与哪个应用程序通信呢。在Socket通信过程中借用了通信过程中借用了TCP和和UDP协议中端口的概念,不同的应用程序可以使用不协议中端口的概念,不同的应用程序可以使用不同的端口进行通信,这样一个主机上就可以同时有多个应用程序进行网络通信了。这同的端口进行通信,这样一个主机上就可以同时有多个应用程序进行网络通信了。这有些类似于电话分机的作用。有些类似于电话分机的作用。(2)服务器应用程序必须早于客户端应用程序启动,并在指定的)服务器应用程序必须早
6、于客户端应用程序启动,并在指定的IP地址和端口上执行地址和端口上执行监听操作。如果该端口被其他应用程序所占用,则服务器应用程序无法正常启动。服监听操作。如果该端口被其他应用程序所占用,则服务器应用程序无法正常启动。服务器处于监听状态就类似于电话接通电话线、等待拨打的状态。务器处于监听状态就类似于电话接通电话线、等待拨打的状态。(3)客户端在申请发送数据时,服务器端应用程序必须有足够的时间响应才能进行正)客户端在申请发送数据时,服务器端应用程序必须有足够的时间响应才能进行正常通信。否则,就好像电话已经响了,但却无人接听一样。在通常情况下,服务器应常通信。否则,就好像电话已经响了,但却无人接听一样
7、。在通常情况下,服务器应用程序都需要具备同时处理多个客户端请求的能力,如果服务器应用程序设计得不合用程序都需要具备同时处理多个客户端请求的能力,如果服务器应用程序设计得不合理或者客户端的访问量过大,都有可能导致无法及时响应客户端的情况。理或者客户端的访问量过大,都有可能导致无法及时响应客户端的情况。(4)使用)使用Socket协议进行通信的双方还必须使用相同的通信协议,协议进行通信的双方还必须使用相同的通信协议,Socket支持的底支持的底层通信协议包括层通信协议包括TCP和和UDP两种。在通信过程中,双方还必须采用相同的字符编码格两种。在通信过程中,双方还必须采用相同的字符编码格式,而且按照
8、双方约定的方式进行通信。这就好像在通电话的时候双方都采用对方能式,而且按照双方约定的方式进行通信。这就好像在通电话的时候双方都采用对方能理解的语言进行沟通一样。理解的语言进行沟通一样。(5)在通信过程中,物理网络必须保持畅通,否则通信将会中断。)在通信过程中,物理网络必须保持畅通,否则通信将会中断。(6)通信结束后,服务器端和客户端应用程序都可以中断它们之间的连接。)通信结束后,服务器端和客户端应用程序都可以中断它们之间的连接。Socket编程的层次结构编程的层次结构5.1.2 Socket的服务方式和类型的服务方式和类型p在在SocketSocket通信中,套接字分为通信中,套接字分为3 3
9、种类型种类型,即流式套接字(,即流式套接字(SOCK_STREAMSOCK_STREAM)、数)、数据报式套接字(据报式套接字(SOCK_DGRAMSOCK_DGRAM)和原始套)和原始套接字(接字(SOCK_RAWSOCK_RAW)。)。1流式套接字流式套接字p 流式套接字提供面向连接的、可靠的数据传输服务流式套接字提供面向连接的、可靠的数据传输服务,可以无差错地发送数据。传输数据可以是双向的,可以无差错地发送数据。传输数据可以是双向的字节流,即应用程序采用全双工方式,通过套接字字节流,即应用程序采用全双工方式,通过套接字同时传输和接收数据。同时传输和接收数据。p 应用程序可以通过流传递有序
10、的、不重复的数据。应用程序可以通过流传递有序的、不重复的数据。所谓所谓“有序有序”指数据包按发送顺序送达目的地址,指数据包按发送顺序送达目的地址,所谓所谓“不重复不重复”指一个特定的数据包只能获取一次指一个特定的数据包只能获取一次。p 如果必须保证数据能够可靠地传送到目的地、并且如果必须保证数据能够可靠地传送到目的地、并且数据量很大时,可以采用流式套接字传输数据。文数据量很大时,可以采用流式套接字传输数据。文件传输协议(件传输协议(FTPFTP)即采用流式套接字传输数据。)即采用流式套接字传输数据。2数据报式套接字数据报式套接字比较项目比较项目流式套接字流式套接字数据报式套接字数据报式套接字建
11、立和释放连接保证数据到达按发送顺序接收数据通讯数据包含完整的目的地址信息3原始套接字原始套接字p原始套接字是公开的套接字编程接口,原始套接字是公开的套接字编程接口,使用它可以在使用它可以在IPIP层上对套接字进行编程层上对套接字进行编程,发送和接收,发送和接收IPIP层上的原始数据包,例层上的原始数据包,例如如ICMPICMP、TCPTCP和和UDPUDP等协议的数据包。等协议的数据包。5.2 WinSock编程基础编程基础5.2.1 5.2.1 构建构建WinSockWinSock应用程序框架应用程序框架5.2.2 IP5.2.2 IP地址的表示形式地址的表示形式5.2.1 构建构建WinS
12、ock应用程序框架应用程序框架p WinSockWinSock包含两个主要的版本,即包含两个主要的版本,即WinSock1WinSock1和和WinSock2WinSock2。在使用。在使用WinSock 1.1WinSock 1.1时,需要引用头文件时,需要引用头文件winsock.hwinsock.h和库文件和库文件wsock32.libwsock32.lib,代码如下:,代码如下:#include#include #pragma comment(lib, wsock32.lib) #pragma comment(lib, wsock32.lib) p 在在Visual Studio 20
13、05Visual Studio 2005中,通常使用中,通常使用WinSock 2.2WinSock 2.2实现网络通信的实现网络通信的功能,则需要引用头文件功能,则需要引用头文件winsock2.hwinsock2.h和库文件和库文件ws2_32.libws2_32.lib,代码,代码如下:如下:#include #include #pragma comment(lib, ws2_32.lib)#pragma comment(lib, ws2_32.lib)使用使用WinSock 2.2实现网络通信的应用程序框架实现网络通信的应用程序框架#include #include #pragma c
14、omment(lib, ws2_32.lib)#pragma comment(lib, ws2_32.lib)/ / 主函数主函数int _tmain(int argc, _TCHARint _tmain(int argc, _TCHAR* * argv) argv) / WSADATA / WSADATA 结构体主要包含了系统所支持的结构体主要包含了系统所支持的WinsockWinsock版本信息版本信息 WSADATA wsaData; WSADATA wsaData; / / 初始化初始化Winsock 2.2Winsock 2.2if( WSAStartup( MAKEWORD(2,2
15、), &wsaData) != 0 ) if( WSAStartup( MAKEWORD(2,2), &wsaData) != 0 ) printf( WSAStartup printf( WSAStartup 无法初始化!无法初始化!); ); return 0; return 0; / / 使用使用WinSockWinSock实现网络通信实现网络通信/ ./ ./ / 最后应该做一些清除工作最后应该做一些清除工作 if( WSACleanup() = SOCKET_ERROR ) if( WSACleanup() = SOCKET_ERROR ) printf( WSACleanup pr
16、intf( WSACleanup 出错!出错!); ); return 0;return 0; 结构体结构体WSADATA用于存储调用用于存储调用WSAStartup()WSAStartup()函数后返回的函数后返回的Windows SocketWindows Socket数据数据。typedef struct WSAData typedef struct WSAData WORD wVersion; WORD wVersion; WORD wHighVersion; WORD wHighVersion;#ifdef _WIN64#ifdef _WIN64 unsigned short iMa
17、xSockets; unsigned short iMaxSockets; unsigned short iMaxUdpDg; unsigned short iMaxUdpDg; char FAR char FAR * * lpVendorInfo; lpVendorInfo; char szDescriptionWSADESCRIPTION_LEN+1; char szDescriptionWSADESCRIPTION_LEN+1; char szSystemStatusWSASYS_STATUS_LEN+1; char szSystemStatusWSASYS_STATUS_LEN+1;#
18、else#else char szDescriptionWSADESCRIPTION_LEN+1; char szDescriptionWSADESCRIPTION_LEN+1; char szSystemStatusWSASYS_STATUS_LEN+1; char szSystemStatusWSASYS_STATUS_LEN+1; unsigned short iMaxSockets; unsigned short iMaxSockets; unsigned short iMaxUdpDg; unsigned short iMaxUdpDg; char FAR char FAR * *
19、lpVendorInfo; lpVendorInfo;#endif#endif WSADATA, FAR WSADATA, FAR * * LPWSADATA; LPWSADATA;结构体结构体WSADATA的各字段说明的各字段说明字段字段含义含义wVersionWindows Sockets DLL期望调用者使用的Windows Sockets规范的版本,为WORD类型。高位字节中存储副版本号,低位字节中存储高版本号。可以使用MAKEWORD()函数返回该值,例如MAKEWORD(2, 2)wHighVersionWindows Sockets DLL可以支持的Windows Sockets
20、规范的最高版本szDescription以null结尾的ASCII字符串。Windows Sockets DLL将对Windows Sockets实现的描述复制到该字符串中,最多可以包含256个字符szSystemStatus以null结尾的ASCII字符串。Windows Sockets DLL将有关状态或配置信息复制到该字符串中iMaxSockets单个进程可以打开的最大套接口数量。Windows Sockets可以提供一个全局的套接口,为每个进程分配套接口资源。程序员可以使用该多好数字作为Windows Sockets是否可以被应用程序使用的原始依据iMaxUdpDgWindows So
21、ckets应用程序能够发送或接收的最大UDP数据包大小,单位为字节。如果实现方式没有限制,则iMaxUdpDg等于0lpVendorInfo指向销售商数据结构的指针WSAStartup()函数函数intint WSAStartupWSAStartup( ( IN WORD IN WORD wVersionRequestedwVersionRequested, , OUT LPWSADATA OUT LPWSADATA lpWSADatalpWSAData ); );参数说明如下:参数说明如下:p wVersionRequestedwVersionRequested,Windows Socket
22、s DLLWindows Sockets DLL规定调用者可以使规定调用者可以使用的用的Windows SocketsWindows Sockets规范的版本,为规范的版本,为WORDWORD类型。高位字节中存类型。高位字节中存储副版本号,低位字节中存储高版本号。可以使用储副版本号,低位字节中存储高版本号。可以使用MAKEWORD()MAKEWORD()函函数返回该值,例如数返回该值,例如MAKEWORD(2, 2)MAKEWORD(2, 2)。p lpWSADatalpWSAData,指向,指向WSADATAWSADATA结构体的指针,用于接收结构体的指针,用于接收Windows Windo
23、ws SocketsSockets执行的数据。执行的数据。【例【例5.1】p通过一个控制台应用程序实例来演示初始化通过一个控制台应用程序实例来演示初始化Windows SocketsWindows Sockets并返回结果的方法。假定项目名称为并返回结果的方法。假定项目名称为WSAStartupWSAStartup,主程序,主程序WSAStartup.cppWSAStartup.cpp的代码如下的代码如下:#include #include stdafx.hstdafx.h #include #include #pragma comment(lib, ws2_32.lib)#pragma co
24、mment(lib, ws2_32.lib)#include #include intint _ _tmaintmain( (intint argcargc, _TCHAR, _TCHAR* * argvargv) / / WSADATA WSADATA 结构体主要包含了系统所支持的结构体主要包含了系统所支持的WinsockWinsock版本信息版本信息 WSADATA WSADATA wsaDatawsaData; ; / / 初始化初始化Winsock 2.2Winsock 2.2 if if( ( WSAStartupWSAStartup( MAKEWORD(2,2), &( MAKEW
25、ORD(2,2), &wsaDatawsaData) != 0 ) ) != 0 ) printfprintf( ( WSAStartupWSAStartup 无法初始化!无法初始化!); ); return return 0; 0; / / 显示显示wsaDatawsaData中的数据中的数据 printfprintf(Version: %(Version: %d.%dd.%dn, LOBYTE(n, LOBYTE(wsaData.wVersionwsaData.wVersion), HIBYTE(), HIBYTE(wsaData.wVersionwsaData.wVersion););
26、printfprintf(High Version: %(High Version: %d.%dd.%dn, LOBYTE(n, LOBYTE(wsaData.wHighVersionwsaData.wHighVersion), HIBYTE(), HIBYTE(wsaData.wHighVersionwsaData.wHighVersion);); printfprintf(Description: %sn, (Description: %sn, wsaData.szDescriptionwsaData.szDescription);); printfprintf(System Status
27、: %s, (System Status: %s, wsaData.szSystemStatuswsaData.szSystemStatus);); / / 最后应该做一些清除工作最后应该做一些清除工作 if( if( WSACleanupWSACleanup() = SOCKET_ERROR ) () = SOCKET_ERROR ) printfprintf( ( WSACleanupWSACleanup 出错!出错!); ); printfprintf(nn);(nn); system system(pause); (pause); return return 0;0; 例例5.15.2
28、.2 IP地址的表示形式地址的表示形式p 对于网络管理员或普通用户而言,对于网络管理员或普通用户而言,IPIP地址常用点分法地址常用点分法来表示。即使用来表示。即使用4 4个个02550255的整数表示的整数表示IPIP地址,每个整地址,每个整数之间使用小数点(数之间使用小数点(. .)分隔,例如)分隔,例如。在。在第第3 3章中已经对章中已经对IPIP地址的这种表示形式做了详细的介地址的这种表示形式做了详细的介绍。绍。p 但是在计算机中并不使用点分法来保存但是在计算机中并不使用点分法来保存IPIP地址,因为地址,因为这样会浪费存储空间,而且不便于根
29、据这样会浪费存储空间,而且不便于根据IPIP地址和子网地址和子网掩码计算子网的信息。事实上,在计算机中使用无符掩码计算子网的信息。事实上,在计算机中使用无符号长整数(号长整数(unsigned longunsigned long)来存储和表示)来存储和表示IPIP地址,地址,而且分为网络字节顺序(而且分为网络字节顺序(NBONBO,Network Byte OrderNetwork Byte Order)和主机字节顺序()和主机字节顺序(HBOHBO,Host Byte OrderHost Byte Order)两种格)两种格式。在网络程序设计时必须了解式。在网络程序设计时必须了解IPIP地址
30、的这两种表示地址的这两种表示形式。形式。1网络字节顺序格式网络字节顺序格式p在网络传输过程中,在网络传输过程中,IPIP地址被保存为地址被保存为3232位二进制数。位二进制数。TCP/IPTCP/IP协议规定,在低位协议规定,在低位存储地址中保存数据的高位字节,这种存储顺序格式被称为网络字节顺序。数据存储地址中保存数据的高位字节,这种存储顺序格式被称为网络字节顺序。数据按照按照3232位二进制数为一组进行传输,因为采用网络字节顺序,所以数据的传输顺位二进制数为一组进行传输,因为采用网络字节顺序,所以数据的传输顺序是由高位至低位进行的序是由高位至低位进行的。p在在Visual C+Visual
31、C+中使用结构体中使用结构体in_addrin_addr来保存网络字节顺序格式的来保存网络字节顺序格式的IPIP地址,它的地址,它的定义代码如下:定义代码如下:structstruct in_addrin_addr union union structstruct u_charu_char s_b1,s_b2,s_b3,s_b4; s_b1,s_b2,s_b3,s_b4; S_un_bS_un_b; ; structstruct u_shortu_short s_w1,s_w2; s_w1,s_w2; S_un_wS_un_w; ; u_longu_long S_addrS_addr; ; S
32、_unS_un; ;p参数说明如下:参数说明如下:pS_un_bS_un_b,由,由4 4个个u_charu_char变量组成的主机格式变量组成的主机格式IPIP地址。地址。pS_un_wS_un_w,由,由2 2个个u_shortu_short变量组成的主机格式变量组成的主机格式IPIP地址。地址。pS_addrS_addr,以,以u_longu_long变量表示的主机格式变量表示的主机格式IPIP地址地址inet_addr()pinet_addr()函数的功能是将点分法函数的功能是将点分法IP地址字符串转换为地址字符串转换为in_addr结构体中的结构体中的IP地址格式,它的语法如下:地址
33、格式,它的语法如下:unsigned long inet_addr( const char* cp );p参数参数cp表示点分法表示点分法IP地址字符串。如果调用地址字符串。如果调用inet_addr()函数函数时没有出现错误,则函数返回时没有出现错误,则函数返回unsignedlong类型的网络字节类型的网络字节顺序格式顺序格式IP地址;如果参数地址;如果参数cp不是有效的不是有效的IP地址字符串,则地址字符串,则inet_addr()函数返回函数返回INADDR_NONE。inet_ntoa()p inet_ntoainet_ntoa()()函数的功能是将函数的功能是将in_addrin_
34、addr结构体中的结构体中的IPIP地址转换为点地址转换为点分法分法IPIP地址字符串,它的语法如下:地址字符串,它的语法如下:char FARchar FAR* * inet_ntoainet_ntoa( ( structstruct in_addrin_addr in in ););p 参数参数inin是是in_addrin_addr结构体类型,表示要进行转换的结构体类型,表示要进行转换的IPIP地址,返回结地址,返回结果为果为charchar* *类型的类型的IPIP地址。地址。2主机字节顺序格式主机字节顺序格式p不同的主机在对不同的主机在对IPIP地址进行存储时使用的格地址进行存储时使
35、用的格式也不同。有些操作系统的式也不同。有些操作系统的IPIP地址存储顺序地址存储顺序与网络字节顺序格式相同,而与网络字节顺序格式相同,而Intel x86Intel x86系列系列主机的主机字节顺序格式则与网络字节顺序主机的主机字节顺序格式则与网络字节顺序格式正好相反。格式正好相反。p可以使用可以使用htonlhtonl()()、htonshtons()()、ntohlntohl()()和和ntohsntohs()()这这4 4个函数来实现主机字节顺序格式个函数来实现主机字节顺序格式和网络字节顺序格式之间的转换。和网络字节顺序格式之间的转换。 htonl()函数函数phtonlhtonl()
36、()函数的功能是将函数的功能是将u_longu_long类型的类型的主机字节顺序格式主机字节顺序格式IPIP地址转换为地址转换为TCP/IPTCP/IP网络字节顺序格式,它的语法网络字节顺序格式,它的语法如下:如下:u_longu_long htonlhtonl( ( u_longu_long hostlonghostlong ););htons()函数函数p htonshtons()()函数的功能是将函数的功能是将u_shortu_short类型的主机字节顺序类型的主机字节顺序格式格式IPIP地址转换为地址转换为TCP/IPTCP/IP网络字节顺序格式,它的语网络字节顺序格式,它的语法如下:
37、法如下:u_shortu_short htonshtons( ( u_shortu_short hostshorthostshort );); ntohl()函数函数p ntohlntohl()()函数的功能是将函数的功能是将u_longu_long类型的类型的TCP/IPTCP/IP网络字节网络字节顺序格式顺序格式IPIP地址转换为主机字节顺序格式,它的语法地址转换为主机字节顺序格式,它的语法如下:如下:u_longu_long ntohlntohl( ( u_longu_long netlongnetlong ););ntohs()函数函数p ntohsntohs()()函数的功能是将函数
38、的功能是将u_shortu_short类型的类型的TCP/IPTCP/IP网络字节网络字节顺序格式顺序格式IPIP地址转换为主机字节顺序格式,它的语法如地址转换为主机字节顺序格式,它的语法如下:下:u_shortu_short ntohsntohs( ( u_shortu_short netshortnetshort ););5.3 面向连接的面向连接的Socket编程编程5.3.1 5.3.1 面向连接的面向连接的SocketSocket通信流程通信流程5.3.2 socket()5.3.2 socket()函数函数5.3.3 bind()5.3.3 bind()函数函数5.3.4 list
39、en()5.3.4 listen()函数函数5.3.5 accept()5.3.5 accept()函数函数5.3.6 recv()5.3.6 recv()函数函数5.3.7 send()5.3.7 send()函数函数5.3.8 closesocket()5.3.8 closesocket()函数函数5.3.9 shutdown()5.3.9 shutdown()函数函数5.3.10 connect()5.3.10 connect()函数函数5.3.11 TCP5.3.11 TCP套接字服务器应用程序编程实例套接字服务器应用程序编程实例5.3.12 TCP5.3.12 TCP套接字客户端应用
40、程序编程实例套接字客户端应用程序编程实例5.3.1 面向连接的面向连接的Socket通信流程通信流程服务器程序中调用的服务器程序中调用的Socket函数函数(1 1)调用)调用WSAStartup()WSAStartup()函数加载函数加载Windows SocketsWindows Sockets动态库,然后调用动态库,然后调用socket()socket()函数创建一个流式套接字,返回套接字号函数创建一个流式套接字,返回套接字号s s。(2 2)调用)调用bind()bind()函数将套接字函数将套接字s s绑定到一个已知的地址,通常为本地绑定到一个已知的地址,通常为本地IPIP地址。地址
41、。(3 3)调用)调用listen()listen()函数将套接字函数将套接字s s设置为监听模式,准备好接收来自各设置为监听模式,准备好接收来自各个客户机的连接请求。个客户机的连接请求。(4 4)调用)调用accept()accept()函数等待接受客户端的连接请求。函数等待接受客户端的连接请求。(5 5)如果接收到客户端的请求,则)如果接收到客户端的请求,则accept()accept()函数返回,得到新的套接函数返回,得到新的套接字字nsns。(6 6)调用)调用recv()recv()函数接收来自客户端的数据,调用函数接收来自客户端的数据,调用send()send()函数向客户函数向客
42、户端发送数据。端发送数据。(7 7)与客户端的通信结束后,服务器程序可以调用)与客户端的通信结束后,服务器程序可以调用shutdown()shutdown()函数通函数通知对方不再发送或接收数据,也可以由客户端程序断开连接。断开连接知对方不再发送或接收数据,也可以由客户端程序断开连接。断开连接后,服务器进程调用后,服务器进程调用closesocket()closesocket()函数关闭套接字函数关闭套接字nsns。此后服务器程。此后服务器程序返回第序返回第4 4步,继续等待客户端进程的连接。步,继续等待客户端进程的连接。(8 8)如果要退出服务器程序,则调用)如果要退出服务器程序,则调用cl
43、osesocket()closesocket()函数关闭最初的套函数关闭最初的套接字接字s s。客户端程序在每一步骤中使用的函数客户端程序在每一步骤中使用的函数(1)调用)调用WSAStartup()函数加载函数加载Windows Sockets动动态库,然后调用态库,然后调用socket()函数创建一个流式套接字,返回函数创建一个流式套接字,返回套接字号套接字号s。(2)调用)调用connect()函数将套接字函数将套接字s连接到服务器。连接到服务器。(3)调用)调用send()函数向服务器发送数据,调用函数向服务器发送数据,调用recv()函数函数接收来自服务器的数据。接收来自服务器的数据
44、。(4)与服务器的通信结束后,客户端程序可以调用)与服务器的通信结束后,客户端程序可以调用shutdown()函数通知对方不再发送或接收数据,也可以函数通知对方不再发送或接收数据,也可以由服务器程序断开连接。断开连接后,客户端进程调用由服务器程序断开连接。断开连接后,客户端进程调用closesocket()函数关闭套接字。函数关闭套接字。5.3.2 socket()函数函数p socket()socket()函数用于创建与指定的服务提供者绑定套接字,它的函数用于创建与指定的服务提供者绑定套接字,它的语法如下:语法如下:SOCKET socket(SOCKET socket( intint af
45、af, , intint type, type, intint protocol protocol ););参数参数说明如下:说明如下:p afaf,指定协议的地址家族,通常使用,指定协议的地址家族,通常使用AF_INETAF_INET。p typetype,指定套接字的类型,具体取值如表,指定套接字的类型,具体取值如表5.45.4所示。所示。p protocolprotocol,套接字使用的协议。,套接字使用的协议。套接字类型套接字类型套接字类型套接字类型说说 明明SOCK_STREAM提供顺序、可靠、双向和面向连接的字节流数据传输机制,使用TCP协议SOCK_DGRAM支持面向无连接的数据
46、报,使用UDP协议SOCK_RAW原始套接字,可以用于接收本机网卡上的数据帧或者数据包【例【例5.2】使用使用socket()socket()函数创建一个函数创建一个TCPTCP套接字,代码如下:套接字,代码如下:/ WSADATA / WSADATA 结构体主要包含了系统所支持的结构体主要包含了系统所支持的WinsockWinsock版本信息版本信息WSADATA wsaData; WSADATA wsaData; / / 初始化初始化Winsock 2.2Winsock 2.2if( WSAStartup( MAKEWORD(2,2), &wsaData) != 0 ) if( WSASt
47、artup( MAKEWORD(2,2), &wsaData) != 0 ) printf( WSAStartup printf( WSAStartup 无法初始化!无法初始化!); ); return 0; return 0; / / 显示显示wsaDatawsaData中的数据中的数据printf(Version: %d.%dn, LOBYTE(wsaData.wVersion), HIBYTE(wsaData.wVersion);printf(Version: %d.%dn, LOBYTE(wsaData.wVersion), HIBYTE(wsaData.wVersion);print
48、f(High Version: %d.%dn, LOBYTE(wsaData.wHighVersion), HIBYTE(wsaData.wHighVersion);printf(High Version: %d.%dn, LOBYTE(wsaData.wHighVersion), HIBYTE(wsaData.wHighVersion);printf(Description: %sn, wsaData.szDescription);printf(Description: %sn, wsaData.szDescription);printf(System Status: %s, wsaData
49、.szSystemStatus);printf(System Status: %s, wsaData.szSystemStatus);/ / 创建创建TCPTCP套接字套接字SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);if(s = INVALID_SOCKET)if(s = INVALID_SOCKET) printf(socket error!);printf(socket error!); / / 使用使用TCPTCP套接字
50、套接字s s进行通信进行通信/ / 最后应该做一些清除工作最后应该做一些清除工作 if( WSACleanup() = SOCKET_ERROR ) if( WSACleanup() = SOCKET_ERROR ) printf( WSACleanup printf( WSACleanup 出错!出错!););5.3.3 bind()函数函数p bind()bind()函数可以将本地地址与一个套接字绑定在一起,它的语法函数可以将本地地址与一个套接字绑定在一起,它的语法如下:如下:intint bind( bind( SOCKET s, SOCKET s, constconst structs
51、truct sockaddrsockaddr FAR FAR* * name, name, intint namelennamelen ););p 参数说明如下:参数说明如下:p s s,标识一个未绑定的套接字的描述符。,标识一个未绑定的套接字的描述符。p namename,绑定到套接字,绑定到套接字s s的的sockaddrsockaddr结构体地址。结构体地址。p namelennamelen,参数,参数namename的长度。的长度。p 如果未发生错误,则函数返回如果未发生错误,则函数返回0 0;否则返回;否则返回SOCKET_ERRORSOCKET_ERROR。【例【例5.3】使用使用
52、bind()bind()函数绑定函数绑定TCPTCP套接字到本地地址的套接字到本地地址的90019001端口,代码如下:端口,代码如下:/ / 初始化初始化Winsock 2.2Winsock 2.2/ / / / 创建创建TCPTCP套接字套接字/ / / / 指定绑定的地址指定绑定的地址structstruct sockaddr_insockaddr_in addraddr; ;/ / 地址的长度地址的长度intint addr_lenaddr_len = = sizeofsizeof( (structstruct sockaddr_insockaddr_in););intint port
53、 = 9901; port = 9901;/ / 端口号端口号intint errCodeerrCode; ;/ / 错误代码错误代码【例【例5.3】/ / 定义服务器地址定义服务器地址addr.sin_family =AF_INET;addr.sin_family =AF_INET;/ / 地址家族地址家族addr.sin_port = htons(port); / addr.sin_port = htons(port); / 端口端口addr.sin_addr.s_addr = htonl(INADDR_ANY);addr.sin_addr.s_addr = htonl(INADDR_AN
54、Y);/ / 地址地址/ / 绑定到套接字绑定到套接字errCode = bind(s, (SOCKADDRerrCode = bind(s, (SOCKADDR* *)&addr, addr_len);)&addr, addr_len);if(errCode = SOCKET_ERROR)if(errCode = SOCKET_ERROR) printf(bind error!);printf(bind error!);exit(1);exit(1); / / 监听和接收数据监听和接收数据/ / 最后应该做一些清除工作最后应该做一些清除工作/ / 5.3.4 listen()函数函数p li
55、sten()listen()函数可以将套接字设置为监听接入连接的状态,它的语函数可以将套接字设置为监听接入连接的状态,它的语法如下:法如下:intint listen( listen( SOCKET s, SOCKET s, intint backlog backlog ););参数说明如下:参数说明如下:p s s,指定一个已经绑定(执行了,指定一个已经绑定(执行了bind()bind()函数)但尚未连接的套接字函数)但尚未连接的套接字。p backlogbacklog,指定等待连接队列的最大长度。,指定等待连接队列的最大长度。如果函数执行成功,则返回如果函数执行成功,则返回0 0;否则返回
56、;否则返回SOCKET_ERRORSOCKET_ERROR。可以调用。可以调用WSAGetLastErrorWSAGetLastError()()函数获取错误代码函数获取错误代码 调用调用listen()函数的错误代码函数的错误代码错误代码错误代码说说 明明WSANOTINITIALISED在 调 用 l i s t e n ( ) 函 数 之 前 没 有 成 功 调 用WSAStartup()函数对WinSock进行初始化WSAENETDOWN网络子系统故障WSAEADDRINUSE本地套接字地址已经使用,并且标识为不可重用WSAEINPROGRESS存在一个阻塞的Windows Socke
57、ts 1.1调用,或者Windows Sockets还在处理一个回调函数WSAEINVAL套接字尚未绑定WSAEISCONN套接字已经连接WSAEMFILE没有有效的套接字描述符WSAENOBUFS没有足够的缓冲区空间WSAENOTSOCK指定描述符并不是一个套接字WSAEOPNOTSUPP引用的套接字并不支持listen操作【例【例5.4】p使用使用listen()listen()函数设置套接字的监听状态,代码如下:函数设置套接字的监听状态,代码如下:/ / 初始化初始化Winsock 2.2Winsock 2.2/ / 创建创建TCPTCP套接字套接字/ / 指定绑定的地址指定绑定的地址/
58、 / 定义服务器地址定义服务器地址/ / 绑定到套接字绑定到套接字/ / 切换到监听状态切换到监听状态errCodeerrCode = listen(s, 3); = listen(s, 3);if(if(errCodeerrCode = SOCKET_ERROR) = SOCKET_ERROR) printfprintf(listen error!);(listen error!);exit(1);exit(1); / / 监听和接收数据监听和接收数据/ / 最后应该做一些清除工作最后应该做一些清除工作5.3.5 accept()函数函数p 在服务器端调用在服务器端调用listen()lis
59、ten()函数监听接入连接后,可以调用函数监听接入连接后,可以调用accept()accept()函数函数来等待接受连接请求。来等待接受连接请求。accept()accept()函数的语法如下函数的语法如下:SOCKET accept(SOCKET accept( SOCKET s, SOCKET s, structstruct sockaddrsockaddr FAR FAR* * addraddr, , intint FAR FAR* * addrlenaddrlen ););参数说明如下:参数说明如下:p s s,通过调用,通过调用listen()listen()函数设置为监听状态的套接
60、字。函数设置为监听状态的套接字。p addraddr,输出参数,用于接收接入地址信息。这是一个可选参数,如果不,输出参数,用于接收接入地址信息。这是一个可选参数,如果不关注接入地址,则可以使用关注接入地址,则可以使用NULLNULL。p addrlenaddrlen,输出参数,指定接入地址的长度。这也是一个可选参数。,输出参数,指定接入地址的长度。这也是一个可选参数。p 如果函数调用成功,则返回一个新建的套接字的句柄,该套接字用于实如果函数调用成功,则返回一个新建的套接字的句柄,该套接字用于实现服务器和客户端之前的通信。如果调用失败,则返回现服务器和客户端之前的通信。如果调用失败,则返回INV
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025机动车租赁合同格式
- 2025废弃土地转包合同
- 法律风险评估报告(详尽版)
- 科技与教育融合学生自主学习模式研究
- 大型底栖动物野外采集方法
- 二零二五年度绿色环保电商运营管理合同4篇
- 二零二五年度幼儿园食堂托管承包合同范本4篇
- 2024年华东师大版八年级地理下册月考试卷
- 2025年人教A版九年级历史上册月考试卷含答案
- 2025年湘师大新版八年级历史下册阶段测试试卷含答案
- 无人化农场项目可行性研究报告
- 《如何存款最合算》课件
- 社区团支部工作计划
- 拖欠工程款上访信范文
- 2024届上海市金山区高三下学期二模英语试题(原卷版)
- 学生春节安全教育
- 《wifi协议文库》课件
- 《好东西》:女作者电影的话语建构与乌托邦想象
- 教培行业研究系列(七):出国考培的再研究供需变化的新趋势
- GB/T 44895-2024市场和社会调查调查问卷编制指南
- 道医馆可行性报告
评论
0/150
提交评论