版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、网络游戏编程,二 Winsock编程,为什么使用TCP/IP,TCP/IP软件可以在不同厂商提供的机器环境中运行。这是因为TCP/IP协议软件平台是独立的,不依赖于任何厂商的内部数据表示方法,也不使用仅仅被部分计算机系统所支持的特性。 TCP/IP软件可以为TCP信息段从源到目的地之间的传输提供可靠保障。 TCP/IP标准不指定应用软件与TCP/IP协议软件之间的接口,该标准仅仅对所需功能提出建议。这样做的优点是保证了在不同操作系统中使用TCP/IP协议软件的灵活性与兼容性,为什么使用TCP/IP API,对编程人员来说,利用TCP/IP 协议软件编程过于底层,因为它要求编程人员了解TCP信息
2、段的所有区段,这样的编程过程过于繁重。所以,最好有一套友好的API,可以供编程人员直接调用,以此实现相关功能。目前,被广泛使用的TCP/IP的API主要有: 伯克利UNIX套接字接口发布版(Berkeley UNIX socket interface distribution (BSD) System V UNIX 传输层接口(Transport Layer Interface ,TLI) Windows 套接字接口 (WinSock),套接字(Socket),网络中的通信接口被称为“套接字”。套接字的行为类似一个通信端点(endpoint)。 TCP/IP的套接字接口首先在Berkeley的
3、UNIX机中实现,随后被引入到其它平台。 在Windows中,套接字接口被称为Windows Socket,或WinSock,或Windows Socket API。,TCP/IP网络通信接口,类似 “插座(socket)”,Winsock,WinSock提供了一个函数库,这些函数根据重要性被分为两类: 重要的套接字函数:例如socket(),bind(),accept(),connect()等。 其它辅助函数:例如getserverbyname(),htons() 等,WinSock执行与TCP/IP协议软件的交互功能,WinSock与协议,WinSock是一个接口,而不是协议本身。 Win
4、Sock支持TCP/IP, NetBIOS, IPX/SPX, AppleTalk等网络协议,某些不同协议族接口间通信,相同协议族接口间通信,(在很多情况下,服务器端和客户端使用不同的协议族,即使使用相同的API,也无法通信。),套接字分类,套接字主要分为三类: 流套接字(stream socket):被TCP协议用于实现面向连接的通信,所以也被称为TCP套接字。 数据包套接字(datagram socket):被UDP协议用于实现无连接的通信,所以也被称为UDP套接字。 原始套接字(raw socket):直接使用IP协议,被用于使用ICMP和OSPF的应用程序。在网络游戏程序的编写过程中,
5、不需要使用。,套接字描述符,每一个套接字都被标识为一个无符号整数,这个整数被称为套接字描述符。 一个进程可以为多个并发通信对话打开多个套接字(例如一个web服务器可以同时为多个浏览器服务时)。Windows为每一个进程保留一个套接字描述符表。进程中的每一个套接字都与一个指针相关联,该指针指向了进程套接字描述符表中的一个数据结构。该数据结构保存了socket会话的相关信息,包括了很多域,当应用程序调用一些WinSock函数时,将填写这些域。,字节顺序,不同的计算机可能使用不同的方法表示16位或32位的整数。整数在这些机器中的保存顺序被称为主机字节顺序(host byte order)。,Inte
6、l 80 x86中表示整数0 x060E170A(小端法),Motorola 68000中表示整数0 x060E170A(大端法),字节顺序,TCP/IP指定大端法字节顺序为网络字节顺序(network byte order)。 一些WinSock函数的参数必须使用网络字节顺序。所以WinSock提供了一些转换函数,用于在主机字节顺序和网络字节顺序间进行转换: u_short htons(u_short host_short): u_short ntohs(u_short network_short): u_long htonl(u_long host_long): u_long ntohl(
7、u_long network_long):,端点地址,通用端点地址: Socket具备协议族无关性,可以兼容多种协议族,并定义了如下通用端点地址: struct sockaddr u_short sa_family; /地址家族 char sa_data14;/占位空字符 ; TCP/IP协议中的端点地址: struct sockaddr_in u_short sin_family;/地址家族 u_short sin_port;/端口号 struct in_addr sin_addr;/IP地址 char sin_zero8; /占位空符 ;,端点地址,可见,TCP/IP的端点地址由三部分组成
8、: TCP/IP地址家族:由AF_INET(Address Family for Internet)来表示 端口号:端口号是一个16位的整数,但是有如下使用规则: 01023:已被用于一些常用的网络服务 1024 - 49151:用于用户自定义的服务(最常用的是10245000) 49152 65535:被用于客户端 IP地址:被用于识别特定的计算机。in_addr 这个结构的定义是: struct in_addr u_long s_addr ; /* IP地址 */ ; /其中,s_addr是IP地址。,端点地址,如果我们只使用TCP/IP,则使用sockaddr_in,而不需要使用sock
9、addr。,sockaddr与sockaddr_in的比较,端点地址,使用端点地址实例 例1: struct sockaddr_in ServerAddr; ServerAddr.sin_family = AF_INET; ServerAddr.sin_port = 2000; ServerAddr.sin_addr.s_addr = htonl (2662729535); 服务器IP地址为158.182.7.63(对应的十进制数即2662729535)。 例2: struct sockaddr_in ServerAddr; ServerAddr.sin_family = AF_INET; S
10、erverAddr.sin_port = 2000; ServerAddr.sin_addr.s_addr = htonl(INADDR_ANY); INADDR_ANY代表可以选取主机的任意IP地址。,TCP网络编程,TCP编程过程: 初始化socket 在套接字之间通信 关闭套接字,初始化socket,初始化WinSock DLL 在使用WinSock之前,应用程序调用WSAStartup(),这样Windows将链接WinSock DLL,并为该应用程序分配所需要的资源。 WSAStartup() 参数1:指定所要求的WinSock的版本 参数2:返回实际被使用的WinSock的版本信息
11、 返回值:为0的时候表明成功装载了socket,如果不是则表示没有正常装载。创建没有成功的原因通常是因为操作系统不支持要求的版本。 例如: #define WSVERS MAKEWORD(2, 0) WSADATA wsadata ; WSAStartup ( WSVERS, ,初始化socket,WinSock是伯克利版UNIX BSD的伯克利套接字版本4.3扩展到Windows的BSD套接字Windows扩展API,如下几个版本 1.0 1.1 2.0 1.1版本以下,链接winsock.h并且连接wsock32.lib 2.0 版本包含winsock2.h,连接ws2_32.lib,初始
12、化socket,typedef struct WSAData WORD wVersion;/装载的socket版本 WORD wHighVersion;/最高支持的socket版本 #ifdef _WIN64 unsigned short iMaxSockets;/最大套接字创建数 unsigned short iMaxUdpDg;/UDP数据最大长度 char FAR * lpVendorInfo; char szDescriptionWSADESCRIPTION_LEN+1; /描述信息 char szSystemStatusWSASYS_STATUS_LEN+1; /运行状态 #else
13、 char szDescriptionWSADESCRIPTION_LEN+1; char szSystemStatusWSASYS_STATUS_LEN+1; unsigned short iMaxSockets; unsigned short iMaxUdpDg; char FAR * lpVendorInfo; #endif WSADATA;,初始化socket,创建一个Socket 程序调用socket()函数,创建一个新的套接字,该套接字可用做TCP联系的端点。 socket() 参数1:协议家族。使用TCP/IP,则指定为PF_INET(Protocol Family for th
14、e InterNET),或AF_INET。 参数2:所创建的套接字的类型。例如,创建TCP所需的流套接字,则指定为SOCK_STREAM;创建UDP所需的数据报套接字,则指定为SOCK_DGRAM;创建原始套接字,则指定为SOCK_RAW。 参数3:除非创建原始套接字,否则可以简单的指定为0。 函数返回一个新创建的套接字的套接字描述符。 示例如下: SOCKET s; s = socket( PF_INET, SOCK_STREAM, 0 );,初始化socket,为套接字指定一个端点地址 创建套接字后,服务器端必须为该套接字分配端点地址。根据该地址,客户端才能识别服务器端的套接字,并向服务器
15、发送请求。服务器调用bind()函数将端口地址与新创建的套接字进行绑定。 bind() 参数1:服务器端socket描述符 参数2:需要绑定的服务器端端点地址 参数3:第2个参数的长度 返回值:当返回值是0的时候,表示成功绑定,当发生其他错误的时候返回SOCKET_ERROR,具体的错误可以通过WSAGetLastError获得 示例: struct sockaddr_in ServerAddr; /在ServerAddr中填写服务器端的端点地址 bind ( s, (struct sockaddr *) ,套接字间通信,客户端初始化一个TCP连接: 在创建一个socket后,客户端调用con
16、nect()建立一个与服务器端的TCP连接。 connect() 参数1:客户端socket描述符 参数2:服务器端端点地址 参数3:第2个参数的长度 示例: struct sockaddr_in ServerAddr; /在ServerAddr中指定所需要连接的服务器端的端点地址 connect ( s, (struct sockaddr *),套接字间通信,服务器端监听连接请求 在创建套接字后,服务器端调用listen(),将套接字置为被动模式(等待连接模式)。随后套接字将开始监听并接受来自客户端的连接。 可能有多个客户端向服务器发送连接请求。listen()将要求操作系统将连接请求加入一
17、个等待队列。只有TCP编程需要调用listen()。 listen() 参数1:服务器端的套接字 参数2:等待队列的最大长度 示例: listen(s, 5); ,套接字间通信,服务器端接受一个连接请求 服务器端调用accept()函数,从队列中获取下一个连接请求。随后服务器端为这个连接请求创建一个新的套接字,并返回这个新的套接字的描述符。accept ()函数只被用于TCP编程中的流套接字。 accept() 参数1:服务器端socket描述符 参数2:发出连接请求的客户端端点地址 参数3:第2个参数的长度 示例: struct sockaddr_in ClientAddr; int len
18、; SOCKET nsock; len = sizeof ( ClientAddr ); nsock = accept( s, (struct sockaddr *) ,套接字间通信,发送消息: 客户端和服务器端都调用send()函数进行数据的发送。send()函数将需要输出的数据拷贝到操作系统内核缓冲区中。当数据在网络中进行传送时,允许应用程序继续执行。如果缓冲区已满,sent()将处于暂时被阻塞的状态,直至缓冲区空间可用。 send() 参数1:发送消息端的socket描述符 参数2:消息文本 参数3:参数2的长度 参数4:可用于处理带外数据等,一般置为0 示例代码如下: char *me
19、ssage=Hello world!; send(s, message, strlen(message), 0);,套接字间通信,接收数据: TCP连接中,客户端和服务器端都通过recv()函数接收数据。在调用recv()前,应用程序必须分配一个缓冲区,用于保存所接收到的数据。recv()用于为指定的socket获取数据,将到达的数据拷贝到应用程序指定的缓冲区中。 当没有数据到达时,recv()将处于阻塞状态。当有数据到达时,如果应用程序缓冲区可以容纳到达的数据,recv获取数据,返回拷贝的字节数;如果无法容纳所有到达的数据,recv()将拷贝部分数据,将应用缓冲区填满。因此,为了获得完整的信
20、息,可能需要多次调用recv()。,套接字间通信,接收数据: recv() 参数1:获取消息端的socket描述符 参数2:用于保存数据的缓冲区的指针 参数3:保存数据的缓冲区的长度 参数4:可用于处理带外数据等,一般置为0 返回值:本次函数调用中,实际拷贝获得数据的字节数 示例: char buf5, *bptr; int buflen; bptr = buf; buflen = 5; recv(s, bptr, buflen, 0);,关闭连接,1. 关闭套接字: 一旦客户端或服务器端不再需要使用套接字,可用调用closesocket()终止与该套接字关联的TCP连接,并回收该套接字。 c
21、losesocket(s); 参数1:需要关闭的socket描述符 2. 清理: 当应用程序不再需要使用套接字时,必须调用WSACleanup(),回收所有被分配的资源。 WSACleanup();,UDP网络编程,UDP的编程过程: 初始化socket 在套接字之间通信 关闭套接字。,初始化socket,初始化WinSock DLL 在使用WinSock之前,应用程序调用WSAStartup(),这样Windows将链接WinSock DLL,并为该应用程序分配所需要的资源。WSAStartup()的调用方法,同TCP网络编程。 创建一个Socket 程序调用socket()函数,创建一个新
22、的套接字,该套接字可用做TCP联系的端点。socket()的调用方法,同TCP网络编程中的讲解。注意,在UDP编程中,函数参数2需要指定为SOCK_DGRAM。 为套接字指定一个端点地址 创建一个套接字后,服务器端必须为该套接字分配一个端点地址。根据该地址,客户端才能向服务器端发送数据请求。服务器调用bind()函数将端口地址与新创建的套接字进行绑定。bind()的调用方法,同TCP网络编程。,套接字间通信,在UDP编程中,服务器端与客户端的通信过程与TCP编程区别较大,主要表现为: 服务器端不再需要通过调用listen()监听客户端连接请求,也不再需要accept()接收客户端连接请求 客户端不再通过connect()发出连接请求 服务器端与客户端不再使用recv()和send(),而是使用recvfrom()和sendto()在套接字间接收或发送消息,套接字间通信,套接字间发送数据: 客户端和服务器端都调用sendto()函数进行数据的发送。 sendto() 参数1:发送消息端的socket描述符 参数2:消息文本 参数3:参数2的长度 参数4:可用于处理带外数据等,一般置为0 参数5:指向接收方地址结构的指针 参数6:地址结构的长度 返回值:总共发出字节数,套接字间通信,套接字间接收数据: UDP连接中,客户端和服务器端都通过recvfrom()函数接收数据。 rec
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 铜管乐器制作工安全综合测试考核试卷含答案
- 井矿盐卤水净化工风险评估模拟考核试卷含答案
- 蔬菜栽培工岗前潜力考核试卷含答案
- 第15讲 光合作用和细胞呼吸的综合分析 高中生物第一轮总复习
- 2026年9月开学第一课收心教育课件(小升初学生):静下心来全力以“复”
- 2026年水生产处理工岗位职业技能资格知识考试题及答案
- 临时围挡设施验收使用保证措施
- 2026年安全操作培训测试题含答案
- 2026年全国煤矿安全管理人员资格考试真题库及答案
- 2026年秋季初中班主任青春期心理健康教育课件
- 2026年中职市场营销(市场营销基础知识)试题及答案
- 2026山东鲁东南水资源配置有限公司社会招聘笔试参考题库及答案详解
- 2026年辽宁高级档案职称考试(档案管理概论)模拟试题及答案
- 2026年中级注册安全工程师安全生产法律法规模拟题库及答案
- 2026年湖南岳阳现代物流集团有限公司招聘11人笔试参考题库及答案详解
- 2026年秋季教育学专业开学第一课 职业发展前景分析教学设计
- 2026秋小学英语人教版(PEP)六年级上册教学计划
- 医院关于不合理医疗检查专项治理自查自查自纠总结
- 2026人教版四年级数学上册第四单元第3课《速度、时间和路程》课件
- 2026年贵州省纪委监委公开遴选公务员笔试试题及答案解析
- 2026年《中华人民共和国妇女权益保障法》知识竞赛题库(含答案)
评论
0/150
提交评论