




已阅读5页,还剩10页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
Windows Socket 网络编程(二) 套接字编程原理作者: 冰点工作室 小鹰一、客户机/服务器模式在TCP/IP网络中两个进程间的相互作用的主机模式是客户机/服务器模式(Client/Server model)。该模式的建立基于以下两点:1、非对等作用;2、通信完全是异步的。客户机/服务器模式在操作过程中采取的是主动请示方式:首先服务器方要先启动,并根据请示提供相应服务:(过程如下)1、打开一通信通道并告知本地主机,它愿意在某一个公认地址上接收客户请求。2、等待客户请求到达该端口。3、接收到重复服务请求,处理该请求并发送应答信号。4、返回第二步,等待另一客户请求5、关闭服务器。客户方:1、打开一通信通道,并连接到服务器所在主机的特定端口。2、向服务器发送服务请求报文,等待并接收应答;继续提出请求3、请求结束后关闭通信通道并终止。二、基本套接字为了更好说明套接字编程原理,给出几个基本的套接字,在以后的篇幅中会给出更详细的使用说明。1、创建套接字socket()功能:使用前创建一个新的套接字格式:SOCKET PASCAL FAR socket(int af,int type,int procotol);参数:af: 通信发生的区域type: 要建立的套接字类型procotol: 使用的特定协议2、指定本地地址bind()功能:将套接字地址与所创建的套接字号联系起来。格式: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;/保留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()与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_set 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类型的参数才是最重要的;第一个FD_SET型的参数readfds是表示要被检查是否可读的 Sockets,把你想要接收数据的那个套接字放在这里;第二个FD_SET参数ritefds是表示要被检查是否可写的 Sockets,将你要发送数据的套接字放在这里;还有个FD_SET参数exceptfds是表示要被检查是否有错误的 Sockets select() 函数的第五个参数timeout,是让我们用来设定 select 函数要等待(block)多久。兹述说如下: (1)如果 timeout 设为NULL,那么 select() 就会一直等到至少某 一个 socket 的事件成立了才会 return,这和其他的 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; select( ., &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, *set) - 检查 s 是否存在於 set 中 参数 readfds、writefds、及 exceptfds 都是 called by value- result;而called by value-result的意思就是说,我们在将参数传给系统时,要先设启始值,并将这些参数的位址(address)告诉系统;而系统则会利用到这些值来做些运算或其他用途,最后并将结果再写回这些参数的位址中。 因此这些参数的值在传入前和函数返回后,可能会不同;所以每次调用 select() 前,对这些参数一定要重新设定它们的值。 假设我们要检查 socket 1 和 2 目前是否可以用来传送资料,以及 socket 3 是 否有资料可读;我们不打算检查 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, 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 FAR *readfds, fd_set FAR *writefds, fd_set FAR *exceptfds, const struct timeval FAR *timeout ); 第一个参数不管,是兼容目的,最后的是超时标准,select是阻塞操作 当然要设置超时事件. 接着的三个类型为fd_set的参数分别是用于检查套节字的可读性,可写性,和列外数据性质. 我举个例子 比如recv(), 在没有数据到来调用它的时候,你的线程将被阻塞 如果数据一直不来,你的线程就要阻塞很久.这样显然不好. 所以采用select来查看套节字是否可读(也就是是否有数据读了) 步骤如下 socket 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 不知道你现在明白没有.另,由于这段时间没忙这,有错误不负责任.呵呵. 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) 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(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) /等待用户请求到来 SOCKET 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); #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;/创建监听的套接字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(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)/等待用户请求到来SOCKET 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);注意:需要包含头文件,并且在工程设置的link里面加上ws32_2.dll 如果在VC中还有一个简单的加载套接字的方法: C+代码 if (!AfxSocketInit() AfxMessageBox(套接字加载失败!); return false; if (!AfxSocketInit()AfxMessageBox(套接字加载失败!);return false;这个不需要包含上面注里面的头文件和ws2_32.lib库就可以实现加载套接字。 2、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) 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();/把U_LONG的主机字节顺序转换为TCP/IP网络字节顺序 addrSrv.sin_family=AF_INET; addrSrv.sin_port=htons(6000); /向服务器发送请求 connect(sockClient,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR); /接受数据 char recBuf100; recv(sockClient,recBuf,100,0); printf(%sn,recBuf); /发送数据 send(s
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年驾考刷题宝典试题及答案
- 慢性阻塞性肺疾病合并肺鳞癌护理查房
- 2014年7月国开电大法律事务专科《行政法与行政诉讼法》期末纸质考试试题及答案
- 安徽省合肥市包河区2023-2024学年高三上学期期中考试化学试题含参考答案
- 2025 年小升初上海市初一新生分班考试语文试卷(带答案解析)-(人教版)
- 吉林省2025年上半年一级注册建筑师《建筑材料与构造》:门窗洞口大小考试试题
- 川师大一中初2025级(八年级下)三月月考数学试题
- 湖南省长沙市雨花区雅礼实验毓秀学校2024-2025学年七年级下学期期末考试数学试题(含部分答案)
- 2025年江苏省镇江市句容二中中考物理一模试卷-自定义类型(含答案)
- 酒店委托会议合同范本
- 海洋岩土工程的挑战与机遇
- 《高中生物学习方法》课件
- 锐器伤管理制度
- 患者隐私保护培训课件1
- 《长生生物科技股份有限公司内部控制问题分析》
- 室内儿童水上乐园建设项目市场调研报告
- 中国老年危重患者营养支持治疗指南(2023版)解读
- 文明施工扬尘治理专项方案
- 中医院科研工作管理核心制度汇总
- 等速肌力测试单关节或关节链不同运动模式以及运动角速度下的肌力参数
- 工资条(标准模版)
评论
0/150
提交评论