ImageVerifierCode 换一换
格式:DOCX , 页数:9 ,大小:23.17KB ,
资源ID:7306726      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/7306726.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(Socket编程分析.docx)为本站会员(b****6)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

Socket编程分析.docx

1、Socket编程分析C+ Socket编程步骤sockets(套接字)编程有三种,流式套接字(SOCK_STREAM),数据报套接字(SOCK_DGRAM),原始套接字(SOCK_RAW);基于TCP的socket编程是采用的流式套接字。服务器端编程的步骤:1:加载套接字库,创建套接字(WSAStartup()/socket();2:绑定套接字到一个IP地址和一个端口上(bind();3:将套接字设置为监听模式等待连接请求(listen();4:请求到来后,接受连接请求,返回一个新的对应于此次连接的套接字(accept();5:用返回的套接字和客户端进行通信(send()/recv();6:返

2、回,等待另一连接请求;7:关闭套接字,关闭加载的套接字库(closesocket()/WSACleanup()。客户端编程的步骤:1:加载套接字库,创建套接字(WSAStartup()/socket();2:向服务器发出连接请求(connect();3:和服务器端进行通信(send()/recv();4:关闭套接字,关闭加载的套接字库(closesocket()/WSACleanup()。第一式: 加载/释放Winsock库:1.加载方法:WSADATA wsa;/*初始化socket资源*/if (WSAStartup(MAKEWORD(1,1),&wsa) != 0) return; /代

3、表失败2.释放方法:WSACleanup();第二式: 构造SOCKET:1.服务端:构造监听SOCKET,流式SOCKET. SOCKETListen_Sock= socket(AF_INET, SOCK_STREAM, 0)2.客户端:构造通讯SOCKET,流式SOCKET.SOCKETClient_Sock= socket(AF_INET, SOCK_STREAM, 0)第三式:配置监听地址和端口:1.服务端: SOCKADDR_INserverAddrZeroMemory(char *)&serverAddr,sizeof(serverAddr);serverAddr.sin_fami

4、ly =AF_INET;serverAddr.sin_port = htons(1234); /*本地监听端口:1234*/serverAddr.sin_addr.s_addr = htonl(INADDR_ANY); /*有IP*/第四式: 绑定SOCKET:1.服务端:绑定监听SOCKET.bind(Listen_Sock,(struct sockaddr *)&serverAddr,sizeof(serverAddr)第五式: 服务端/客户端连接:1.服务端:等待客户端接入. SOCKETCommand_Sock= accept(Listen_Sock, .)2.客户端:请求与服务端连接

5、.int ret = connect(Client_Sock, .)第六式: 收/发数据:1.服务端:等待客户端接入.char buf1024. 接收数据:recv(Command_Sock,buf, .)或 发送数据:send(Command_Sock,buf, .)2.客户端:请求与服务端连接.char buf1024. 发送数据:send(Client_Sock,buf, .)或 接收数据:recv(Client_Sock,buf, .)第七式: 关闭SOCKET:1.服务端:关闭SOCKET. closesocket(Listen_Sock)closesocket(Command_So

6、ck)2.客户端:关闭SOCKET.closesocket(Client_Sock)备注:第一步:socket(AF_INET, SOCK_STREAM, 0)解读struct sockaddr_in Lewis; Lewis.sin_family = AF_INET; Lewis.sin_port = htons(80); Lewis.sin_addr.s_addr = inet_addr(202.96.134.133);/ sin_addr.s_addr也是头文件规定 memset(Lewis.sin_zero,0,sizeof(Lewis.sin_zero);分析:我们设置了一个名叫Le

7、wis的套接字地址,它基于TCP/IP协议,因此sin_family的值为AF_INET,这个是雷打不动的,只要使用TCP/IP协议簇,该值就是AF_INET;htons是端口函数,以后介绍,这就表示设置了端口号为80;SOCKETListen_Sock= socket(AF_INET, SOCK_STREAM, 0)函数原型:int socket(int domain, int type, int protocol);参数说明:domain:协议域,又称协议族(family)。常用的协议族有AF_INET、AF_INET6、AF_LOCAL(或称AF_UNIX,Unix域Socket)、AF

8、_ROUTE等。协议族决定了socket的地址类型,在通信中必须采用对应的地址,如AF_INET决定了要用ipv4地址(32位的)与端口号(16位的)的组合、AF_UNIX决定了要用一个绝对路径名作为地址。type:指定Socket类型。常用的socket类型有SOCK_STREAM、SOCK_DGRAM、SOCK_RAW、SOCK_PACKET、SOCK_SEQPACKET等。流式Socket(SOCK_STREAM)是一种面向连接的Socket,针对于面向连接的TCP服务应用。数据报式Socket(SOCK_DGRAM)是一种无连接的Socket,对应于无连接的UDP服务应用。protoc

9、ol:指定协议。常用协议有IPPROTO_TCP、IPPROTO_UDP、IPPROTO_STCP、IPPROTO_TIPC等,分别对应TCP传输协议、UDP传输协议、STCP传输协议、TIPC传输协议。注意:1.type和protocol不可以随意组合,如SOCK_STREAM不可以跟IPPROTO_UDP组合。当第三个参数为0时,会自动选择第二个参数类型对应的默认协议。第二步:ntohs, ntohl, htons,htonl的比较和详解ntohs =net to host short int 16位htons=host to net short int 16位ntohl =net to

10、host long int 32位htonl=host to net long int 32位网络字节顺序NBO(Network Byte Order)按从高到低的顺序存储,在网络上使用同一的网络字节顺序,可避免兼容性问题;主机字节顺序HBO(Host Byte Order)不同的机器HBO不相同,与CPU的设计有关,数据的顺序是由CPU决定的,而与操作系统无关;如Intel x86结构下,short型数0x1234表示为34 12,int型数0x12345678表示为78 56 34 12;如IBM power PC结构下,short型数0x1234表示为 12 34,int型数0x1234

11、5678表示为 12 34 56 78.由于这个原因,不同体系结构的机器之间不能直接通信,所以要转换成一种约定的顺序,也就是网络字节顺序,其实就是如同power pc那样的顺序。在PC开发中有ntohl和htonl函数可以用来进行网络字节和主机字节的转换ntohs()简述:将一个无符号短整形数从网络字节顺序转换为主机字节顺序。#include u_short PASCAL FAR ntohs( u_short netshort);netshort:一个以网络字节顺序表达的16位数。注释:本函数将一个16位数由网络字节顺序转换为主机字节顺序。返回值:ntohs()返回一个以主机字节顺序表达的数。

12、htons()简述:将主机的无符号短整形数转换成网络字节顺序。#include u_short PASCAL FAR htons( u_short hostshort);hostshort:主机字节顺序表达的16位数。注释:本函数将一个16位数从主机字节顺序转换成网络字节顺序。返回值:htons()返回一个网络字节顺序的值。第三步:关于地址INADDR_ANY就是指定地址为0.0.0.0的地址,这个地址事实上表示不确定地址,或“所有地址”、“任意地址”。 一般来说,在各个系统中均定义成为0值。在Internet地址族中,一个名字包括几个组成部分,对于SOCK_DGRAM和SOCK_STREAM

13、类套接口,名字由三部分组成:主机地址,协议号(显式设置为UDP和TCP)和用以区分应用的端口号。如果一个应用并不关心分配给它的地址,则可将Internet地址设置为INADDR_ANY,或将端口号置为0。如果Internet地址段为INADDR_ANY,则可使用任意网络接口,且在有多种主机环境下可简化编程。如果端口号置为0,则Windows套接口实现将给应用程序分配一个值在1024到5000之间的唯一的端口。应用程序可在bind()后用getsockname()来获知所分配的地址,但必需注意的是,getsockname()只有在套接口连接成功后才会填写Internet地址,这是由于在多种主机环

14、境下若干种Internet地址都是有效的。第四步:永久循环那么while(1)其中1代表一个常量表达式,他永远不会等于0。所以,循环会一直执行下去。第五步 绑定地址int bind(int sockfd, const struct sockaddr *addr,socklen_t *addrlen);bind()把用addr指定的地址赋值给用文件描述符代表的套接字sockfd。addrlen指定了以addr所指向的地址结构体的字节长度。一般来说,该操作称为“给套接字命名”。通常,在一个SOCK_STREAM套接字接收连接之前,必须通过bind()函数用本地地址为套接字命名。备注:调用bind(

15、)函数之后,为socket()函数创建的套接字关联一个相应地址,发送到这个地址的数据可以通过该套接字读取与使用。备注:bind()函数并不是总是需要调用的,只有用户进程想与一个具体的地址或端口相关联的时候才需要调用这个函数。如果用户进程没有这个需要,那么程序可以依赖内核的自动的选址机制来完成自动地址选择,而不需要调用bind()函数,同时也避免不必要的复杂度。在一般情况下,对于服务器进程问题需要调用bind()函数,对于客户进程则不需要调用bind()函数。bind(sockSrv,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR)(SOCKADDR*)&addrSrv将

16、&addrSrv转换为套接字地址指针备注:(sockaddr*)&servAddr是什么意思servAddr是个结构体取servAddr的地址然后转化为指向sockaddr类型(sockaddr*)的指针第六步 listenint listen(SOCKET sock, int backlog); /Windows缓冲区的长度(能存放多少个客户端请求)可以通过 listen() 函数的 backlog 参数指定,但究竟为多少并没有什么标准,可以根据你的需求来定,并发量小的话可以是10或者20。如果将 backlog 的值设置为SOMAXCONN,就由系统来决定请求队列长度,这个值一般比较大,可

17、能是几百,或者更多。注意:listen() 只是让套接字处于监听状态,并没有接收请求。接收请求需要使用 accept() 函数。第二个参数是你监听客户端的最大个数,如连接到主机上的客户端超过其数listen则会返回一个错误代号。至于队列放在哪可以不关心,可以认为是一个缓冲区。参数sockfd被listen函数作用的套接字,sockfd之前由socket函数返回。在被socket函数返回的套接字fd之时,它是一个主动连接的套接字,也就是此时系统假设用户会对这个套接字调用connect函数,期待它主动与其它进程连接,然后在服务器编程中,用户希望这个套接字可以接受外来的连接请求,也就是被动等待用户来

18、连接。由于系统默认时认为一个套接字是主动连接的,所以需要通过某种方式来告诉系统,用户进程通过系统调用listen来完成这件事。参数backlog这个参数涉及到一些网络的细节。进程处理一个一个连接请求的时候,可能还存在其它的连接请求。因为TCP连接是一个过程,所以可能存在一种半连接的状态,有时由于同时尝试连接的用户过多,使得服务器进程无法快速地完成连接请求。如果这个情况出现了,服务器进程希望内核如何处理呢?内核会在自己的进程空间里维护一个队列以跟踪这些完成的连接但服务器进程还没有接手处理或正在进行的连接,这样的一个队列内核不可能让其任意大,所以必须有一个大小的上限。这个backlog告诉内核使用

19、这个数值作为上限。毫无疑问,服务器进程不能随便指定一个数值,内核有一个许可的范围。这个范围是实现相关的。很难有某种统一,一般这个值会小30以内。第七步listen() 只是让套接字进入监听状态,并没有真正接收客户端请求,listen() 后面的代码会继续执行,直到遇到 accept()。accept() 会阻塞程序执行(后面代码不能被执行),直到有新的请求到来。第八步 send函数int send(SOCKET s, const char *buf, int len, int flags);参数描述: SOCKET s 发送端套接字描述符 const char *buf 应用程序要发送的数据的

20、缓冲区(想要发送的数据) int len 实际要发送的字节数 int flags 一般置为0即可 同步Socket的send函数的执行流程如下: 调用该函数时,send先比较待发送数据的长度len与套接字s的发送缓冲区的长度(区别于buf),如果len大于s的发送缓冲区的长度,则函数返回SOCKET_ERROR; 如果len小于或者等于s发送缓冲区的长度,那么send先检查协议是否正在发送s的发送缓冲区中的数据: a.如果是在发送,就等待协议将数据发送完毕。 b.如果没有开始发送s的缓冲区中的数据,那么send就比较s的发送缓冲区的剩余空间和len的大小: 如果len大于发送缓冲区剩余空间大小

21、(不足放入剩余发送缓冲区),send就一直 等待协议把s发送缓冲区中的数据发送完;如果len小于发送缓冲区剩余空间大小,就仅仅把buf中的数据copy到发送缓冲区的剩余空间里(send函数返回时并不代表send把s的缓冲区的数据(buf)传到连接的另一端,而是协议传输的,send仅仅是把buf中的数据copy到s的发送缓冲区的剩余空间中)。如果send函数copy数据成功,就返回实际copy的字节数,如果send在copy数据时出现错误,那么send就返回SOCKET_ERROR;如果send在等待协议传送数据时断开网络,那么send函数也返回SOCKET_ERROR。 要注意send函数把b

22、uf中的数据成功copy到s的发送缓冲的剩余空间后就返回了,但是此时这些数据并不一定马上被传到连接的另一端。如果协议在后续的传送过程中出现网络错误的话,那么下一个Socket函数就会返回SOCKET_ERROR.(每一个除send之外的Socket函数在执行的最开始总要先等待套接字的发送缓冲区中的数据被协议传送完毕才能继续,如果在等待时出现网络错误,那么该Socket函数就返回SOCKET_ERROR)。 recv函数:int recv (SOCKET s, char* buf ,int len, int flags);参数描述: SOCKET s 发送端套接字描述符 const char *

23、buf 应用程序存放接收的数据的缓冲区 int len buf的长度 int flags 一般置为0即可 同步Socket的recv函数的执行流程如下: 调用recv函数时,recv先等待s的发送缓冲区中的数据被协议发送完毕: a.如果协议在传送s的发送缓冲区中的数据时出现网络错误,那么recv函数返回SOCKET_ERROR; b.如果s的发送缓冲区中的数据被协议成功发送完毕或者没有数据时,recv先检查套接字s的接收缓冲区的情况: 如果s接收缓冲区中没有数据或者协议正在接收数据,那么recv就一直等待,直到协议把数据接收完毕。当协议把数据接收完毕,recv函数就把s的接收缓冲区中的数据co

24、py到buf中(注意协议接收到的数据可能大于buf的长度,所以在这种情况下要调用几次recv函数才能把s的接收缓冲中的数据copy完。recv函数仅仅是copy数据,真正接收数据是协议来完成的),recv函数返回其实际copy的字节数。 如果recv在copy时出错,那么它返回SOCKET_ERROR;如果recv函数在等待协议接收数据时网络中断了,那么它返回0。 第八步 数据传输socketSOCKET sockConn=accept(sockSrv,(SOCKADDR*)&addrClient,&len);Accept函数返回给的也是socket sprintf(sendBuf,Welco

25、me %s to here!,inet_ntoa(addrClient.sin_addr); /inet_ntoa将sin_addr储存的IP(数值)转换成字符串形式比如:(127.0.0.1)。intaccept(int s,struct sockaddr * addr,int * addrlen)服务程序调用accept函数从处于监听状态的流套接字s的客户连接请求队列中取出排在最前的一个客户请求,并且创建一个新的套接字来与客户套接字创建连接通道,如果连接成功,就返回新创建的套接字的描述符,以后与客户套接字交换数据的是新创建的套接字;如果失败就返回 INVALID_SOCKET。该函数的第一

26、个参数指定处于监听状态的流套接字;操作系统利用第二个参数来返回新创建的套接字的地址结构;操作系统利用第三个参数来返回新创建的套接字的地址结构的长度。关键备注:创建新的套接字,取监听的套接字,第二个新创建的地址结构,第三个位长度int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);参数sockfd:套接字描述符,该套接口在listen()后监听连接。addr:(可选)指针,指向一缓冲区,其中接收为通讯层所知的连接实体的地址。Addr参数的实际格式由套接口创建时所产生的地址族确定。addrlen:(可选)指针,输入参数,

27、配合addr一起使用,指向存有addr地址长度的整型数。一些地址的写法:addrSrv.sin_addr.S_un.S_addr=htonl(INADDR_ANY);addrSrv.sin_addr.S_un.S_addr=inet_addr(127.0.0.1);char sendBuf50; sprintf(sendBuf,Welcome %s to here!,inet_ntoa(addrClient.sin_addr)字符串格式化命令,主要功能是把格式化的数据写入某个字符串中功能把格式化的数据写入某个字符串缓冲区。sprintf头文件stdio.hsprintf原型int sprintf( char *buffer, const char *format, argument );sprintf参数列表buffer:char型指针,指向将要写入的字符串的缓冲区。format:格式化字符串。argument.:可选参数,可以是任何类型的数据。

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1