Socket编程之C++实现.docx_第1页
Socket编程之C++实现.docx_第2页
Socket编程之C++实现.docx_第3页
Socket编程之C++实现.docx_第4页
Socket编程之C++实现.docx_第5页
已阅读5页,还剩1页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

一、 套接字的编程学习1.1 套接字的基本概念套接字类型:数据流套接字(SOCK_STREAM):对应TCP协议。数据报套接字(SOCK_DGRAM):对应UDP协议。原始套接字(SOCKET_RAW):包含了IP、TCP等信息头,可获得更多网络信息。完整的网间通信包含:协议、本地地址、本地端口号、远地地址、远地端口号1.2 基本套接字的系统调用 为了更好地说明套接字编程原理,下面给出几个基本套接字的系统调用说明。 1.2.1 创建套接字socket() 应用程序在使用套接字前,首先必须拥有一个套接字,系统调用socket()向应用程序提供创建套接字的手段,其调用格式如下: SOCKET PASCAL FAR socket(int af, int type, int protocol); 参数af:指定通信发生的区域,UNIX系统支持的地址族有:AF_UNIX、AF_INET、AF_NS等,而DOS、WINDOWS中仅支持AF_INET;参数type:描述要建立的套接字的类型;参数protocol:说明该套接字使用的特定协议,如果调用者不希望特别指定使用的协议,则置为0,使用默认的协议。根据这三个参数建立一个套接字,并将相应的资源分配给它,同时返回一个整型套接字号。socket()系统调用实际上指定了相关五元组中的“协议”这一元。 1.2.2 指定本地地址bind() 将本地主机地址和本地端口与所创建的套接字号联系起来,其调用格式如下: int PASCAL FAR bind(SOCKET s, const struct sockaddr FAR * name, int namelen); 参数s:是由socket()调用返回的套接字描述符(整型套接字号)。参数name:是赋给套接字s的本地地址,其长度可变,结构随通信域的不同而不同,TCP/IP协议使用的地址结构如下:struct sockaddr_in short sin_family; /*AF_INET*/ u_short sin_port; /*16位端口号,网络字节顺序*/ struct in_addr sin_addr;/*32位IP地址,网络字节顺序*/ char sin_zero8; /*保留*/ 网络字节顺序:不同的计算机存放多字节值的顺序不同,有的机器在起始地址先存放低位字节,有的先存高位字节。为保证数据的正确性,在网络协议中须指定网络字节顺序。TCP/IP协议使用16位整数和32位整数的高价先存格式,它们均含在协议头文件中。参数namelen:表明了name的长度。 如果没有错误发生,bind()返回0。否则返回值SOCKET_ERROR。 1.2.3 建立套接字连接connect()与accept() connect()用于建立连接。无连接的套接字进程也可以调用connect(),这样就不必每次都指定目的地址。而accept()用于使服务器等待来自某客户进程的实际连接。 int PASCAL FAR connect(SOCKET s, const struct sockaddr FAR * name, int namelen); 参数s:是欲建立连接的本地套接字描述符。参数name:为指向对方套接字地址结构的指针。参数namelen:对方套接字地址结构长度。 如果没有错误发生,connect()返回0。否则返回值SOCKET_ERROR。 SOCKET PASCAL FAR accept(SOCKET s, struct sockaddr FAR* addr, int FAR* addrlen); 参数s:为本地套接字描述符,在用做accept()调用的参数前应该先调用过listen()。addr :指向客户方套接字地址结构的指针,用来接收连接实体的地址。Addrlen:为客户方套接字地址结构的长度。如果没有错误发生,accept()返回一个SOCKET类型的值,表示接收到的套接字的描述符。否则返回值INVALID_SOCKET。 accept()用于面向连接服务器。参数addr和addrlen存放客户方的地址信息。调用前,参数addr 指向一个初始值为空的地址结构,而addrlen 的初始值为0;调用accept()后,服务器等待从编号为s的套接字上接受客户连接请求,而连接请求是由客户方的connect()调用发出的。当有连接请求到达时,accept()调用将请求连接队列上的第一个客户方套接字地址及长度放入addr 和addrlen,并创建一个与s有相同特性的新套接字号。新的套接字可用于处理服务器并发请求。 四个套接字系统调用,socket()、bind()、connect()、accept(),可以完成一个完全五元相关的建立。socket()指定五元组中的协议元。bind()指定五元组中的本地二元,即本地主机地址和端口号,其用法与是否面向连接有关:在服务器方,无论是否面向连接,均要调用bind();在客户方,若采用面向连接,则可以不调用bind(),而通过connect()自动完成。若采用无连接,客户方必须使用bind()以获得一个唯一的地址。 1.2.4 监听连接listen() 此调用用于面向连接服务器,表明它愿意接收连接。listen()需在accept()之前调用,其调用格式如下: int PASCAL FAR listen(SOCKET s, int backlog); 参数s:标识一个本地已建立、尚未连接的套接字号,服务器愿意从它上面接收请求。Backlog:表示请求连接队列的最大长度,用于限制排队请求的个数,目前允许的最大值为5。如果没有错误发生,listen()返回0。否则它返回SOCKET_ERROR。数据传输send()与recv() 当一个连接建立以后,就可以传输数据了。常用的系统调用有send()和recv()。 int PASCAL FAR send(SOCKET s, const char FAR *buf, int len, int flags); 参数s:为已连接的本地套接字描述符。buf :指向存有发送数据的缓冲区的指针,其长度由len 指定。Flags:指定传输控制方式,如是否发送带外数据等。如果没有错误发生,send()返回总共发送的字节数。否则它返回SOCKET_ERROR。 int PASCAL FAR recv(SOCKET s, char FAR *buf, int len, int flags); 参数s:为已连接的套接字描述符。Buf:指向接收输入数据缓冲区的指针,其长度由len 指定。Flags:指定传输控制方式,如是否接收带外数据等。如果没有错误发生,recv()返回总共接收的字节数。如果连接被关闭,返回0。否则它返回SOCKET_ERROR。Flags参数可以是0或者是以下的组合:MSG_DONTROUTE:不查找路由表。是send函数使用的标志,这个标志告诉IP协议,目的主机在本地网络上面,没有必要查找路由表。MSG_OOB:表示可以接收和发送带外的数据。MSG_PEEK:是recv函数的使用标志,表示只是从系统缓冲区中读取内容,而不清除系统缓冲区的内容。这样下次读的时候,仍然是一样的内容。一般在有多个进程读写数据时可以使用这个标志。MSG_WAITAL:是recv函数的使用标志,表示等到所有的信息到达时才返回。使用这个标志的时候recv会一直阻塞,直到指定的条件满足,或者是发生了错误。 1)当读到了指定的字节时,函数正常返回,返回值等于len。 2)当读到了文件的结尾时,函数正常返回,返回值小于len。3)当操作发生错误时,返回-1,且设置错误为相应的错误号(errno)。1.2.6 数据传输sendto()与recvfrom() Sendto()用于在无连接套接字上发送消息。Recvfrom()可以记录发送者的地址,该地址与sendto所指定的地址结构完全相同。 int sendto(int sockfd,const void *msg,int len,unsigned int flags,struct sockaddr *to,int tolen) int recvfrom(int sockfd,void *buf,int len,unsigned int flags,struct sockaddr * from,int *fromlen) sockfd: 表示套接字描述符。buf: 发送或接收的缓冲区。len: 缓冲区及大小。recvfrom负责从sockfd接收数据,如果from不是NULL,那么在from里面存储了信息来源的情况,如果对信息的来源不感兴趣,可以将from和fromlen设置为NULL。sendto负责向to发送信息,此时在to里面存储了接收信息方的详细信息。1.2.7 数据传输recvmsg()和sendmsg()recvmsg和sendmsg的功能类似于recvfrom和sendto,只不过将一些信息放入了一个结构中。 int recvmsg(int sockfd,struct msghdr *msg, int flags) int sendmsg(int sockfd,struct msghdr *msg, int flags) struct msghdr void *msg_name; int msg_namelen; struct iovec *msg_iov; int msg_iovlen; void *msg_control; int msg_controllen; int msg_flags; struct iovec void *iov_base; /* 缓冲区开始的地址 */ size_t iov_len; /* 缓冲区的长度 */ msg_name和 msg_namelen当套接字是非面向连接时(UDP),它们存储接收和发送方的地址信息。msg_name实际上是一个指向struct sockaddr的指针,msg_name是结构的长度。当套接字是面向连接时,这两个值应设为NULL. msg_iov和msg_iovlen指出接受和发送的缓冲区内容。msg_iov是一个结构指针,msg_iovlen指出这个结构数组的大小。 msg_control和msg_controllen这两个变量是用来接收和发送控制数据时的 msg_flags指定接受和发送的操作选项,和recv,send的选项一样。1.2.8 关闭套接字closesocket() 与Shutdown()closesocket()关闭套接字s,并释放分配给该套接字的资源;如果s涉及一个打开的TCP连接,则该连接被释放。closesocket()的调用格式如下: BOOL PASCAL FAR closesocket(SOCKET s); 参数s:待关闭的套接字描述符。如果没有错误发生,closesocket()返回0。否则返回值SOCKET_ERROR。 int shutdown(int sockfd,int howto) TCP连接是双向的(是可读写的),当我们使用close时,会把读写通道都关闭,有时侯我们希望只关闭一个方向,这个时候我们可以使用shutdown。针对不同的howto,系统会采取不同的关闭方式. Howto = 0这个时候系统会关闭读通道,但是可以继续写。Howto = 1关闭写通道,但是可以继续读。 Howto = 2关闭读写通道。1.2.9 输入/输出多路复用select() select()调用用来检测一个或多个套接字的状态。对每一个套接字来说,这个调用可以请求读、写或错误状态方面的信息。请求给定状态的套接字集合由一个fd_set结构指示。在返回时,此结构被更新,以反映那些满足特定条件的套接字的子集,同时, select()调用返回满足条件的套接字的数目,其调用格式如下: int PASCAL FAR select(int nfds, fd_set FAR * readfds, fd_set FAR * writefds, fd_set FAR * exceptfds, const struct timeval FAR * timeout); 参数nfds:指明被检查的套接字描述符的值域,此变量一般被忽略。 参数readfds:指向要做读检测的套接字描述符集合的指针,调用者希望从中读取数据。参数writefds:指向要做写检测的套接字描述符集合的指针。Exceptfds:指向要检测是否出错的套接字描述符集合的指针。Timeout:指向select()函数等待的最大时间,如果设为NULL则为阻塞操作。select()返回包含在fd_set结构中已准备好的套接字描述符的总数目,或者是发生错误则返回SOCKET_ERROR。 1.3 数据转换和网络信息函数 1.3.1字节顺序转换函数在网络上面有着许多类型的机器,这些机器在表示数据的字节顺序是不同的,比如Intel采用的字节顺序称为小头方式,即低字节在前,高字节在后的方式,而标准的网络顺序是大头方式,即高字节在前,低字节在后的方式。将0x12345678写入到以0x0000开始的内存中,则结果为:大头方式小头方式1.0x0000 0x12 0x342.0x0001 0x34 0x123.0x0002 0x56 0x784.0x0003 0x78 0x56为了统一起来,Windows socket有专门的字节顺序转换函数。 unsigned long int htonl(unsigned long int hostlong) unsigned short int htons(unisgned short int hostshort) unsigned long int ntohl(unsigned long int netlong) unsigned short int ntohs(unsigned short int netshort) 在这四个转换函数中,h 代表host, n 代表 network。s 代表short, l 代表long,第一个函数的意义是将本机器上的long数据转化为网络上的long, 其它几个函数的意义类似。1.3.2 IP和域名的转换在网络上标志一台机器可以用IP或者是用域名,那么怎么进行转换呢? struct hostent *gethostbyname(const char *hostname) struct hostent *gethostbyaddr(const char *addr,int len,int type) 在中有struct hostent的定义 struct hostent char *h_name; /* 主机的正式名称 */ char *h_aliases; /* 主机的别名 */ int h_addrtype;/* 主机的地址类型 AF_INET*/ int h_length; /* 主机的地址长度 对于IP4 是4字节32位*/ char *h_addr_list; /* 主机的IP地址列表 */ #define h_addr h_addr_list0 /* 主机的第一个IP地址*/ gethostbyname可以将机器名(如 )转换为一个结构指针.在这个结构里面储存了域名的信息 gethostbyaddr可以将一个32位的IP地址(C0A80001)转换为结构指针. 这两个函数失败时返回NULL 且设置h_errno错误变量,调用h_strerror()可以得到详细的出错信息 1.3.3 字符串的IP和32位的IP转换. 在网络上面IP地址都用点分十进制数字表示(如:),而在struct in_addr结构中用的是32位的IP,为了转换我们可以使用下面两个函数:int inet_aton(const char *cp,struct in_addr *inp) char *inet_ntoa(struct in_addr in) 函数里面a代表ascii,n代表network。第一个函数表示将a.b.c.d的IP转换为32位的IP,,存储在 inp指针里面。第二个是将32位IP转换为a.b.c.d的格式。 1.3.4 服务信息函数 在网络程序里面我们有时候需要知道端口、IP和服务信息,这个时候可以使用以下几个函数 int getsockname(int sockfd,struct sockaddr *localaddr,int *addrlen) int getpeername(int sockfd,struct sockad

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论