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

加入VIP,免费下载
 

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

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

下载须知

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

版权提示 | 免责声明

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

WindowsSocket网络编程.docx

1、WindowsSocket网络编程Windows Socket 网络编程(二) 套接字编程原理作者: 冰点工作室 小鹰一、客户机/服务器模式在TCP/IP网络中两个进程间的相互作用的主机模式是客户机/服务器模式(Client/Server model)。该模式的建立基于以下两点:1、非对等作用;2、通信完全是异步的。客户机/服务器模式在操作过程中采取的是主动请示方式:首先服务器方要先启动,并根据请示提供相应服务:(过程如下)1、打开一通信通道并告知本地主机,它愿意在某一个公认地址上接收客户请求。2、等待客户请求到达该端口。3、接收到重复服务请求,处理该请求并发送应答信号。4、返回第二步,等待另

2、一客户请求5、关闭服务器。客户方:1、打开一通信通道,并连接到服务器所在主机的特定端口。2、向服务器发送服务请求报文,等待并接收应答;继续提出请求3、请求结束后关闭通信通道并终止。二、基本套接字为了更好说明套接字编程原理,给出几个基本的套接字,在以后的篇幅中会给出更详细的使用说明。1、创建套接字socket()功能:使用前创建一个新的套接字格式:SOCKET PASCAL FAR socket(int af,int type,int procotol);参数:af: 通信发生的区域type: 要建立的套接字类型procotol: 使用的特定协议2、指定本地地址bind()功能:将套接字地址与所

3、创建的套接字号联系起来。格式:int PASCAL FAR bind(SOCKET s,const struct sockaddr FAR * name,int namelen);参数:s: 是由socket()调用返回的并且未作连接的套接字描述符(套接字号)。其它:没有错误,bind()返回0,否则SOCKET_ERROR地址结构说明:struct sockaddr_inshort sin_family;/AF_INETu_short sin_port;/16位端口号,网络字节顺序struct in_addr sin_addr;/32位IP地址,网络字节顺序char sin_zero8;/保

4、留3、建立套接字连接connect()和accept()功能:共同完成连接工作格式:int PASCAL FAR connect(SOCKET s,const struct sockaddr FAR * name,int namelen);SOCKET PASCAL FAR accept(SOCKET s,struct sockaddr FAR * name,int FAR * addrlen);参数:同上4、监听连接listen()功能:用于面向连接服务器,表明它愿意接收连接。格式:int PASCAL FAR listen(SOCKET s, int backlog);5、数据传输send

5、()与recv()功能:数据的发送与接收格式:int PASCAL FAR send(SOCKET s,const char FAR * buf,int len,int flags);int PASCAL FAR recv(SOCKET s,const char FAR * buf,int len,int flags);参数:buf:指向存有传输数据的缓冲区的指针。 6、多路复用select()功能:用来检测一个或多个套接字状态。格式:int PASCAL FAR select(int nfds, fd_set FAR * readfds,fd_set FAR * writefds, fd_s

6、et FAR * exceptfds,const struct timeval FAR * timeout);参数:readfds:指向要做读检测的指针writefds:指向要做写检测的指针exceptfds:指向要检测是否出错的指针timeout:最大等待时间select()* 执行同步I/O多路复用。 select函数的参数( int nfds, fd_set readfds, fd_set writefds, fd_set exceptfds, const struct timeval timeout ) 我记得是:第一个是个较为次要的值,设成0就行了。 后面的几个FD_SET类型的参数

7、才是最重要的;第一个FD_SET型的参数readfds是表示要被检查是否可读的 Sockets,把你想要接收数据的那个套接字放在这里;第二个FD_SET参数ritefds是表示要被检查是否可写的 Sockets,将你要发送数据的套接字放在这里;还有个FD_SET参数exceptfds是表示要被检查是否有错误的 Sockets select() 函数的第五个参数timeout,是让我们用来设定 select 函数要等待(block)多久。兹述说如下: (1)如果 timeout 设为NULL,那么 select() 就会一直等到至少某 一个 socket 的事件成立了才会 return,这和其他

8、的 blocking 函数一样。 select( ., NULL ) (2)如果 timeout 的值设为 0, 0 (秒, 微秒),那么 select() 在检查后, 不管有没有 socket 的事件成立,都会马上 return,而不会停留。 timeout.tv_sec = timeout.tv_usec = 0; select( ., &timeout ) (3)如果 timout 设为 m, n,那么就会等到至少某一个 socket 的事件发 生,或是时间到了(m 秒 n 微秒),才会 return。 timeout.tv_sec = m; timeout.tv_usec = n; s

9、elect( ., &timeout ) 返回值:成功 - 符合条件的 Sockets 总数 (若 Timeout 发生,则为 0) 失败 - SOCKET_ERROR (呼叫 WSAGetLastError() 可得知原因) 说明: 使用者可利用此函式来检查 Sockets 是否有资料可被读取,或是有空间可以写入,或是有错误发生。 关于对FD_SET类型的操作,有几个比较重要的宏: FD_ZERO(*set) - 将 set 的值清乾净 FD_SET(s, *set) - 将 s 加到 set 中 FD_CLR(s, *set) - 将 s 从 set 中删除 FD_ISSET(s, *se

10、t) - 检查 s 是否存在於 set 中 参数 readfds、writefds、及 exceptfds 都是 called by value- result;而called by value-result的意思就是说,我们在将参数传给系统时,要先设启始值,并将这些参数的位址(address)告诉系统;而系统则会利用到这些值来做些运算或其他用途,最后并将结果再写回这些参数的位址中。 因此这些参数的值在传入前和函数返回后,可能会不同;所以每次调用 select() 前,对这些参数一定要重新设定它们的值。 假设我们要检查 socket 1 和 2 目前是否可以用来传送资料,以及 socket 3

11、 是 否有资料可读;我们不打算检查 sockets 是否有错误发生,所以 exceptfds 设为 NULL。步骤大致如下: FD_ZERO( &writefds ); FD_ZERO( &readfds ); FD_SET( 1, &writefds ); FD_SET( 2, &writefds ); FD_SET( 3, &readfds ); select( ., &readfds, &writefds, NULL, .) if (FD_ISSET( 1, &writefds ) send( 1, data ); if (FD_ISSET( 2, &writefds ) send( 2

12、, data ); if (FD_ISSET( 3, &readfds ) recv( 3, data );7、关闭套接字closesocket()功能:关闭套接字s格式:BOOL PASCAL FAR closesocket(SOCKET s);三、典型过程图2.1 面向连接的套接字的系统调用时序图2.2 无连接协议的套接字调用时序图2.3 面向连接的应用程序流程图FD_ZERO,FD_ISSET这些都是套节字结合操作宏 看看MSDN上的select函数, 这是在select io 模型中的核心,用来管理套节字IO的,避免出现无辜锁定. int select( int nfds,fd_set

13、 FAR *readfds, fd_set FAR *writefds, fd_set FAR *exceptfds, const struct timeval FAR *timeout ); 第一个参数不管,是兼容目的,最后的是超时标准,select是阻塞操作 当然要设置超时事件. 接着的三个类型为fd_set的参数分别是用于检查套节字的可读性,可写性,和列外数据性质. 我举个例子 比如recv(), 在没有数据到来调用它的时候,你的线程将被阻塞 如果数据一直不来,你的线程就要阻塞很久.这样显然不好. 所以采用select来查看套节字是否可读(也就是是否有数据读了) 步骤如下 socket

14、s; . fd_set set; while(1) FD_ZERO(&set);/将你的套节字集合清空 FD_SET(s, &set);/加入你感兴趣的套节字到集合,这里是一个读数据的套节字s select(0,&set,NULL,NULL,NULL);/检查套节字是否可读, /很多情况下就是是否有数据(注意,只是说很多情况) /这里select是否出错没有写 if(FD_ISSET(s, &set) /检查s是否在这个集合里面, /select将更新这个集合,把其中不可读的套节字去掉 /只保留符合条件的套节字在这个集合里面 recv(s,.); /do something here 不知道你

15、现在明白没有.另,由于这段时间没忙这,有错误不负责任.呵呵. 1、Socket服务器端: Socket服务器端流程如下:加载套接字-创建监听的套接字-绑定套接字-监听套接字-处理客户端相关请求。 下面是孙鑫VC详解里面的服务器端的例子: C+代码 #include #include void main() /加载套接字 WORD wVersionRequested; WSADATA wsaData; int err; wVersionRequested=MAKEWORD(1,1); err=WSAStartup(wVersionRequested,&wsaData); if (err!=0)

16、return; if (LOBYTE(wsaData.wVersion)!=1| HIBYTE(wsaData.wVersion)!=1) WSACleanup(); return; /创建监听的套接字 SOCKET sockSrv=socket(AF_INET,SOCK_STREAM,0); SOCKADDR_IN addrSrv; addrSrv.sin_addr.S_un.S_addr=htonl(INADDR_ANY);/把U_LONG的主机字节顺序转换为TCP/IP网络字节顺序 addrSrv.sin_family=AF_INET; addrSrv.sin_port=htons(60

17、00); /绑定套接字 bind(sockSrv,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR); /将套接字设置为监听模式,准备接受用户请求 listen(sockSrv,5); SOCKADDR_IN addrClient; int len=sizeof(SOCKADDR); printf(%sn,welcome,the serve is started.); while (1) /等待用户请求到来 SOCKET sockConn=accept(sockSrv,(SOCKADDR*)&addrClient,&len); char sendBuf100; sprin

18、tf(sendBuf,welcome %s to ,inet_ntoa(addrClient.sin_addr); /发送数据 send(sockConn,sendBuf,100,0); char revBuf100; /接收数据 recv(sockConn,revBuf,100,0); /打印接受数据 printf(%sn,revBuf); /关闭套接字 closesocket(sockConn); #include #include void main() /加载套接字 WORD wVersionRequested; WSADATA wsaData; int err; wVersionRe

19、quested=MAKEWORD(1,1); err=WSAStartup(wVersionRequested,&wsaData); if (err!=0) return; if (LOBYTE(wsaData.wVersion)!=1| HIBYTE(wsaData.wVersion)!=1) WSACleanup(); return; /创建监听的套接字 SOCKET sockSrv=socket(AF_INET,SOCK_STREAM,0); SOCKADDR_IN addrSrv; addrSrv.sin_addr.S_un.S_addr=htonl(INADDR_ANY);/把U_L

20、ONG的主机字节顺序转换为TCP/IP网络字节顺序 addrSrv.sin_family=AF_INET; addrSrv.sin_port=htons(6000); /绑定套接字 bind(sockSrv,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR); /将套接字设置为监听模式,准备接受用户请求 listen(sockSrv,5); SOCKADDR_IN addrClient; int len=sizeof(SOCKADDR); printf(%sn,welcome,the serve is started.); while (1) /等待用户请求到来 SOCK

21、ET sockConn=accept(sockSrv,(SOCKADDR*)&addrClient,&len); char sendBuf100; sprintf(sendBuf,welcome %s to ,inet_ntoa(addrClient.sin_addr); /发送数据 send(sockConn,sendBuf,100,0); char revBuf100; /接收数据 recv(sockConn,revBuf,100,0); /打印接受数据 printf(%sn,revBuf); /关闭套接字 closesocket(sockConn); 注意:需要包含头文件,并且在工程设置

22、的link里面加上ws32_2.dll 如果在VC中还有一个简单的加载套接字的方法: C+代码 if (!AfxSocketInit() AfxMessageBox(套接字加载失败!); return false; if (!AfxSocketInit() AfxMessageBox(套接字加载失败!); return false; 这个不需要包含上面注里面的头文件和ws2_32.lib库就可以实现加载套接字。 2、Socket客户端: Socket客户端同样需要先加载套接字,然后创建套接字,不过之后不用绑定和监听了,而是直接连接服务器,发送相关请求。 同样贴出孙鑫VC详解里面的客户端的例子:

23、(不是我偷懒,是人家实在写的太好,无法超越 ) C+代码 #include #include void main() /加载套接字 WORD wVersionRequested; WSADATA wsaData; int err; wVersionRequested=MAKEWORD(1,1); err=WSAStartup(wVersionRequested,&wsaData); if (err!=0) return; if (LOBYTE(wsaData.wVersion)!=1| HIBYTE(wsaData.wVersion)!=1) WSACleanup(); return; /创建

24、套接字 SOCKET sockClient=socket(AF_INET,SOCK_STREAM,0); SOCKADDR_IN addrSrv; addrSrv.sin_addr.S_un.S_addr=inet_addr(127.0.0.1);/把U_LONG的主机字节顺序转换为TCP/IP网络字节顺序 addrSrv.sin_family=AF_INET; addrSrv.sin_port=htons(6000); /向服务器发送请求 connect(sockClient,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR); /接受数据 char recBuf100

25、; recv(sockClient,recBuf,100,0); printf(%sn,recBuf); /发送数据 send(sockClient,this is 马亚南1,strlen(this is 马亚南)+1,0); /关闭套接字 closesocket(sockClient); WSACleanup(); #include #include void main() /加载套接字 WORD wVersionRequested; WSADATA wsaData; int err; wVersionRequested=MAKEWORD(1,1); err=WSAStartup(wVers

26、ionRequested,&wsaData); if (err!=0) return; if (LOBYTE(wsaData.wVersion)!=1| HIBYTE(wsaData.wVersion)!=1) WSACleanup(); return; /创建套接字 SOCKET sockClient=socket(AF_INET,SOCK_STREAM,0); SOCKADDR_IN addrSrv; addrSrv.sin_addr.S_un.S_addr=inet_addr(127.0.0.1);/把U_LONG的主机字节顺序转换为TCP/IP网络字节顺序 addrSrv.sin_fa

27、mily=AF_INET; addrSrv.sin_port=htons(6000); /向服务器发送请求 connect(sockClient,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR); /接受数据 char recBuf100; recv(sockClient,recBuf,100,0); printf(%sn,recBuf); /发送数据 send(sockClient,this is 扈修非,strlen(this is 扈修非)+1,0); /关闭套接字 closesocket(sockClient); WSACleanup();需要加载的头文件和库同上

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

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