




已阅读5页,还剩35页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
Socket网络编程指导,2019/6/14,1/37,,什么是Socket?,2019/6/14,2/37,BSD Socket(伯克立套接字)是通过标准的UNIX文件描述符和其它程序通讯的一个方法,目前已经被广泛移植到各个平台。 Socket是独立于具体协议的网络编程接口。在ISO模型中,主要位于会话层和传输层。,Socket的类型,2019/6/14,3/37,流式套接字(SOCK_STREAM) 提供了一个面向连接,可靠的数据传输服务,数据无差错,无重复的发送且按发送顺序接收。内设流量控制,避免数据流超限;数据被看作是字节流,无长度限制。 数据报式套接字(SOCK_DGRAM) 提供了一个无连接服务。数据包以独立包形式被发送,不提供无差错保证,数据可能丢失或重复,并且接收顺序无序。 原始式套接字(SOCK_RAW) 该接口允许对较低层次协议,如IP、ICMP直接访问。,2019/6/14,4/37,Socket所在层次示意图,Application program,Stream Socket Interface,TCP,UDP,Datagram Socket Interface,Raw Socket Interface,IP,Physical and data link layers,基本套接字调用,2019/6/14,5/37,创建套接字 socket(); 绑定本机端口 bind(); 建立连接 connect(); 接受连接 accept(); 监听端口 listen(); 数据传输 send(), recv() 等; 关闭套接字 close();,Socket相关的数据结构,2019/6/14,6/37,struct sockaddr_in short int sin_family; /* 通信类型 */ unsigned short int sin_port; /* 端口号,网络字节顺序*/ struct in_addr sin_addr; /* Internet 地址,网络字节顺序*/ unsigned char sin_zero8; /*没用*/ ; struct in_addr in_addr_t s_addr; /* 存储32bit 的IP地址*/ ,网络字节顺序和主机字节顺序,2019/6/14,7/37,Big-Endian Byte Order:字节的高位在内存中放在存储单元的起始位置,00001010,00010111,00001110,00000110,00001010,00010111,00001110,00000110,Memory,Little-Endian Byte Order : 与Big-Endian相反,A,A+1,A+2,A+3,2019/6/14,8/40,Host byte order( Little-Endian ),16-bit,32-bit,Network byte order(Big-Endian),16-bit,32-bit,htons(),ntohs(),htonl(),ntohl(),网络字节顺序和主机字节顺序的转换,IP地址的转换,2019/6/14,9/37,int inet_aton(const char* strptr, struct in_addr *addrptr); 从点状十进制到32位2进制的转换,如“85” 到 11001010,00100110,01000000,10111001 char *inet_ntoa(struct in_addr inadd); 与inet_aton()的功能相反,相关的内存操作函数,2019/6/14,10/37,void *memset(void *buffer, int c, int count); 把buffer所指内存区域的前count个字节设置成字符c。 void *memcpy(void *dest, void *src, unsigned int count); 由src所指内存区域复制count个字节到dest所指内存区域。 Void bzero(void *s, int n ); 置字节字符串s的前n个字节为零。,域名和IP地址的转换,2019/6/14,11/37,struct hostent *gethostbyname(const char *name);,struct hostent char *h_name; /* 主机的官方域名 */ char *h_aliases; /* 一个以NULL结尾的主机别名数组 */ int h_addrtype; /* 返回的地址类型,在Internet环境下为AF- INET */ int h_length; /* 地址的字节长度 */ char *h_addr_list; /* 一个以0结尾的数组,包含该主机的所有地 址*/ ; #define h_addr h_addr_list0 /*在h-addr-list中的第一个地址*/,建立Socket,2019/6/14,12/37,int socket(int domain, int type, int protocol); 参数说明: domain:通信使用的协议族,即网络的类型,对于 TCP/IP来说,是AF_INET type: SOCK_STREAM / SOCK_DGRAM protocol: 通常为0 返回整形的socket描述符,如果出错,返回-1,Socket的配置,2019/6/14,13/37,Socket描述符是一个指向内部数据结构的指针,它指向描述符表入口。调用Socket()函数时,将建立一个Socket,为一个Socket数据结构分配存储空间。 两个网络程序之间的一个网络连接包括五种信息:通信协议、本地主机地址和端口、远端主机地址和端口。 在使用socket进行网络传输以前,必须配置该socket。 面向连接的socket客户端调用connect()函数在socket数据结构中保存本地和远端信息。 无连接socket的客户端和服务端以及面向连接socket的服务端通过调用bind()函数来配置本地信息。,绑定Socket,2019/6/14,14/37,int bind(int sockfd,struct sockaddr_in *my_addr, int addrlen); sockfd是socket()返回的socket描述符; my_addr是指向包含本机IP地址及端口号等信息的 sockaddr类型的指针; addrlen一般被设置为sizeof(struct sockaddr_in) 成功被调用时返回0;出现错误时返回“-1“,绑定前sockaddr_in的初始化,2019/6/14,15/37,my_addr.sin_family = AF_INET; /选择网络类型为TCP/IP my_addr.sin_addr.s_addr = inet_addr(“22“); my_addr.sin_port = htons( 8888 ); /选择端口8888 addr_len = sizeof(struct sockaddr_in); memset(,建立连接(客户端),2019/6/14,16/37,面向连接的客户程序使用connect函数来配置socket并与远端服务器建立一个TCP连接,其函数原型为: int connect( int sockfd, struct sockaddr_in *serv_addr,int addrlen); serv_addr是包含远端主机IP地址和端口号的指针;addrlen是远端地址结构的长度 成功则返回0,出现错误时返回-1,建立连接(服务器端),2019/6/14,17/37,服务器监听端口:listen函数使socket处于被动的监听模式,并为该socket建立一个输入数据队列,将到达的服务请求保存在此队列中,直到程序处理它们。 int listen(int sockfd, int backlog); backlog:请求连接队列的最大长度 成功返回0,出错返回-1,建立连接(服务器端),2019/6/14,18/37,accept()函数让服务器接收客户的连接请求。在建立好输入队列后,服务器就调用accept函数,然后睡眠并等待客户的连接请求。 int accept(int sockfd, sockaddr_in *addr, int *addrlen); addr是指向sockaddr_in变量的指针,该变量存放提出连接请求服务的主机的信息 返回新的socket描述符,和请求连接进程的地址联系起来在新的socket描述符上进行数据传输操作。原来的socket继续listen,数据传输(1),2019/6/14,19/37,send()和recv()这两个函数用于面向连接的socket上进行数据传输。 send()函数原型为: int send(int sockfd, const void *msg, int len, int flags); sockfd是用来传输数据的socket描述符;msg是指向要发送数据的指针;len是以字节为单位的数据长度;flags一般置为0 send() 返回实际发送的字节数,可能会少于希望发送的数据。在程序中应该将send()的返回值与欲发送的字节数进行比较。当返回值与len不匹配时,应该进行处理。,数据传输(2),2019/6/14,20/37,recv()函数原型为: int recv(int sockfd, void *buf, int len, unsigned int flags); buf 是存放接收数据的缓冲区;len是缓冲区的长度。flags也被置为0。 recv()返回实际接收的字节数,当出现错误时,返回-1,数据传输(3),2019/6/14,21/37,sendto()和recvfrom()用于在无连接的数据报socket方 式下进行数据传输。由于本地socket没有与远端机器建立连接,所以在发送数据时要指明目的地址。 sendto()函数原型为: int sendto(int sockfd, const void *buf,int buflen, unsigned int flags, const struct sockaddr_in *to, int tolen);,数据传输(4),2019/6/14,22/37,recvfrom()函数原型为: int recvfrom(int sockfd,void *buf,int buflen, unsigned int flags,struct sockaddr_in *from,int *fromlen); recvfrom()函数返回接收到的字节数,当出错时返回-1,结束传输,2019/6/14,23/37,close()函数用于释放socket,停止在该socket上的任何数据操作: close(sockfd); 也可以调用shutdown() 来关闭该socket 该函数允许只停止某个方向上的数据传输,而一个方向上的数据传输继续进行。 int shutdown(int sockfd,int how); 参数 how允许为shutdown操作选择以下几种方式: 0-不允许继续接收数据 1-不允许继续发送数据 2-不允许继续发送和接收数据, shutdown在操作成功时返回0,出错时返回-1。,C/S结构,2019/6/14,24/37,服务器端要先启动,提供相应服务: 1:打开一通信通道并告知本地主机,它愿意在某一个公认地址上接收客户请求。 2:等待客户请求到达该端口。 3:接收到服务请求,处理该请求并发送应答信号。 4:返回第二步,等待另一客户请求 5:关闭服务器。,客户端: 1、打开一通信通道,并连接到服务器所在主机的特定端口。 2、向服务器发送服务请求报文,等待并接收应答;继续提出请求 3、请求结束后关闭通信通道并终止。,流程图,2019/6/14,25/37,TCP服务器端 (循环服务器),TCP客户端,socket( ),bind( ),listen( ),accept( ),socket( ),send( ),connect( ),recv( ),recv( ),send( ),close( ),close( ),UDP服务器端,UDP客户端,socket( ),bind( ),listen( ),recvfrom( ),sendto( ),socket( ),bind( ),close( ),close( ),简单的例子,2019/6/14,26/37,int sockfd, newsockfd,addr_len, sendnum; struct sockaddr_in my_addr, their_addr; char * msg = “welcome”; sockfd = socket( AF_INET, SOCK_STREAM, 0 ); /建立socket my_addr.sin_family = AF_INET; /选择网络类型为TCP/IP my_addr.sin_addr.s_addr = inet_addr(“22“); my_addr.sin_port = htons( 8888 ); /选择端口8888 addr_len = sizeof( struct sockaddr_in); memset( /监听,等待连接,等待连接队列最大长度为10,简单的例子(续),2019/6/14,27/37,While( 1 ) newsockfd = accept( sockfd, (struct sockaddr *),阻塞与非阻塞(1),2019/6/14,28/37,阻塞函数:指其完成指定的任务之前不允许程序调用另一个函数,在Windows下还会阻塞本线程消息的发送。 eg: recv( ) ,当socket工作在阻塞模式的时候,如果没有数据的情况下调用该函数,则当前线程会被挂起,直到有数据为止。 非阻塞函数:指操作启动之后,如果可以立即得到结果就返回结果,否则返回表示结果需要等待的错误信息,不等待任务完成函数就返回。,使用非阻塞I/O的方式:select() 例子: while(1)/执行循环 一边输出一边也不要忘了输入 FD_ZERO(,2019/6/14,29/37,阻塞与非阻塞(2),2019/6/14,30/37,在Berkeley socket函数部分中,不涉及网络I/O、本地端工作的函数是非阻塞函数 在Berkeley socket函数部分中,网络I/O的函数是可阻塞函数,也就是它们可以阻塞执行,也可以不阻塞执行。这些函数都使用了一个socket,如果它们使用的socket是阻塞的,则这些函数是阻塞函数;如果它们使用的socket是非阻塞的,则这些函数是非阻塞函数。,并发服务器,2019/6/14,31/37,TCP服务器端(并发服务器),socket( ),bind( ),listen( ),accept( ),send( ),recv( ),close( ),fork( ) /派生新进程,close( ),主进程在accept之后派生新进程,然后主进程继续listen,处理新的连接请求 新进程自行和客户端通信,新进程和主进程抢占CPU,WinSock API,2019/6/14,32/37,WinSock是一个基于Socket模型的API,在Microsoft Windows操作系统类中使用。 它在Berkeley接口函数的基础之上,还增加了基于消息驱动机制的Windows扩展函数。 Winscok1.1只支持TCP/IP网络,WinSock2.0增加了对更多协议的支持。,Windows下的Socket编程(1),2019/6/14,33/37,和linux下基本相同,需要包含winsock2.h 需要使用Ws_32.lib,可以用以下语句通告程序编译时调用该库: #pragma comment(lib,“Ws2_32.lib“) ; WinSock以DLL的形式提供,在调用任何WinSock API之前,必须调用函数WSAStartup()进行初始化,最后,调用函数WSACleanUp()作清理工作。,Windows下的Socket编程(2),2019/6/14,34/37,WSADATA wsd; /设置WINSOCK的版本 WORD wVersionRequested=MAKEWORD(2,2); WSAStartup(wVersionRequested,Windows下的Socket编程(3),2019/6/14,35/37,MFC提供了两个类CAsyncSocket和CSocket来封装WinSock API,提供了更简单的网络编程接口。 CAsyncSocket在较低层次上封装了WinSock API,缺省情况下,使用该类创建的socket是非阻塞的socket,所有操
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 通信业务租用合同范本
- 装修物品工程合同范本
- 道路清淤维修合同范本
- 私人地皮转让合同范本
- 酒吧委托协议合同范本
- 道路施工补充合同范本
- 车辆合法租赁合同范本
- 资金变动协议合同模板
- 软件系统转让合同范本
- 活动板房外包合同范本
- 小学生美术素养的综合评价体系构建与实践
- 《混凝土质量通病》课件
- 化学反应中的表示课件九年级化学(2024)上册
- 乳腺肿物手术配合护理
- 2024年在图书管理员培训上的讲话范例(3篇)
- 《天津市主要葫芦科作物对CGMMV的抗性鉴定及耐热性研究》
- 《语言学概论》教案(完整版)
- 《成本会计》高职财经类专业全套教学课件
- 2023年合肥市肥东县大学生乡村医生专项计划招聘考试真题
- 2024年共青团团课考试测试题库及答案
- 跨平台智能汽车故障预警
评论
0/150
提交评论