网络IPC:网络socket的学习

相关函数:socket、bind、listen、connect、accept、send、recv、close、shutdown

其函数在Linux下的头文件为:#include<sys/socket.h>

套接字描述符 :套接字是通信端点的抽象,如使用文件描述符访问文件,应用程序用套接字描述符访问套接字。应用程序通过访问该函数创建的套接字实现对数据的发送和接收。套接字描述符在UNIX系统被当为一种文件描述符。

1.创建一个套接字,调用socket函数

函数原型:int socket (int domain, int type, int protocal);

返回值:若函数调用成功,返回套接字描述符;若出错,返回-1。

1)参数domain:确定通信的特性,包括地址格式。各个域都有自己表示地址的格式,而表示各个域的常数都以AF_开头,意指地址族。

| 域domain | 描述 |

| AF_INET | IPv4因特网域 |

| AF_INET6 | IPv6因特网域 |

| AF_UNIX | UNIX域 |

| AF_UPSPEC | 未指定 |

2) 参数type:确定套接字的类型,进一步确定通信特征。

| 类型type | 描述 |

| SOCK_DGRAM | 支持UDP连接(无连接状态的消息) |

| SOCK_RAW | RAW类型,提供原始网络协议访问 |

| SOCK_SEQPACKET | 序列化包,提供一个序列化的、可靠的、双向的基本连接的数据传输通道,数据长度定常。每次调用读系统调用时数据需要将全部数据读出 |

| SOCK_STREAM | Tcp连接,提供序列化的、可靠的、双向连接的字节流。支持带外数据传输 |


3) 参数protocol:通常是0,表示为给定的域和套接字类型选择默认协议。


| 协议protocol | 描述 |

| SOCK_DGRAM | 支持UDP连接(无连接状态的消息) |

| SOCK_RAW | RAW类型,提供原始网络协议访问 |

| SOCK_SEQPACKET | 序列化包,提供一个序列化的、可靠的、双向的基本连接的数据传输通道,数据长度定常。每次调用读系统调用时数据需要将全部数据读出 |

| SOCK_STREAM | Tcp连接,提供序列化的、可靠的、双向连接的字节流。支持带外数据传输 |


2.将套接字与地址关联,调用bind

函数函数原型为:int bind( int sockfd , const struct sockaddr * my_addr, socklen_t addrlen);返回值:

若函数调用成功,返回0;若出错,返回-1。

1)参数sockfd:为socket函数创建的套接字。

2)参数my_addr:为sockaddr * 类型的网络地址结构体 。

3)参数addrlen:为网络地址的长度。 当socket函数返回一个描述符时,只是存在于其协议族的空间中,并没有分配一个具体的协议地址(这里指IPv4/IPv6和端口号的组合),bind函数可以将一组固定的地址绑定到sockfd上。通常服务器在启动的时候都会绑定一个众所周知的协议地址,用于提供服务,客户就可以通过它来接连服务器;而客户端可以指定IP或端口也可以都不指定,未分配则系统自动分配。这就是为什么通常服务器端在listen之前会调用bind(),而客户端就不会调用,而是在connect()时由系统随机生成一个。


3.监听套接字的状态,调用listen

函数函数原型为:int listen(int sock_fd, int backlog);

返回值:若函数调用成功,返回0;若出错,返回-1。

1)参数sock_fd:为将要监听的套接字。

2)参数 backlog: 指定同时能处理的最大连接要求, 如果连接数目达此上限则client 端将收到ECONNREFUSED 的错误.


4.建立连接,调用connect

函数函数原型:int connect(int sockfd,const struct sockaddr *addr, socklen_t addrlen);

返回值:若函数调用成功,返回0;若出错,返回-1

1)参数sockfd:是本地描述符。

2)参数addr:为服务器地址。

3)参数addrlen:是socket地址长度。


5.获得连接请求并建立连接,调用accept

函数函数原型:int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);返回值:若函数调用成功,返回套接字描述符;若出错,返回-1

1)参数sockfd: 利用系统调用socket()建立的套接字描述符,通过bind()绑定到一个本地地址(一般为服务器的套接字),并且通过listen()一直在监听连接;

2)参数addr: 指向struct sockaddr的指针,该结构用通讯层服务器对等套接字的地址(一般为客户端地址)填写,返回地址addr的确切格式由套接字的地址类别(比如TCP或UDP)决定;若addr为NULL,没有有效地址填写,这种情况下,addrlen也不使用,应该置为NULL。addr是个指向局部数据结构sockaddr_in的指针,这就是要求接入的信息本地的套接字(地址和指针)。

3)参数addrlen:一个值结果参数,调用函数必须初始化为包含addr所指向结构大小的数值,函数返回时包含对等地址(一般为服务器地址)的实际数值。addrlen是个局部整形变量,设置为sizeof(struct sockaddr_in)。 备注:若不关心客户端标识,可以将参数addr和len设为NULL。


6.发送数据,调用send

函数函数原型:int send( SOCKET sock_fd,char *buf,int len,int flags );

返回值:若函数调用成功,返回发送的字节数;若出错,返回-1。

1)参数sock_fd:发送端套接字描述符(非监听描述符)。

2)参数buf:应用要发送数据的缓存。

3)参数len:实际要发送的数据长度。

4)参数flags:调用执行方式。一般设该值为0。

send先比较待发送数据的长度len和套接字sock_fd的发送缓冲的长度(因为待发送数据是要copy到套接字sock_fd的发送缓冲区的): 如果len大于sock_fd的发送缓冲区的长度,该函数返回SOCKET_ERROR; 如果len小于或者等于sock_fd的发送缓冲区的长度,那么send先检查协议是否正在发送sock_fd的发送缓冲中的数据。如果是就等待协议把数据发送完,如果协议还没有开始发送sock_fd的发送缓冲中的数据或者sock_fd的发送缓冲中没有数据,那么 send就比较sock_fd的发送缓冲区的剩余空间和len: 如果len大于剩余空间大小send就一直等待协议把s的发送缓冲中的数据发送完;如果len小于剩余空间大小send就仅仅把buf中的数据copy到剩余空间里;如果send函数copy数据成功,就返回实际copy的字节数,如果send在copy数据时出现错误,那么send就返回SOCKET_ERROR;如果send在等待协议传送数据时网络断开的话,那么send函数也返回SOCKET_ERROR。即使send成功返回,也并不表示连接的另一端的进程就一定接收了数据。我们所能保证的只是当send成功返回时,数据已经被无错误地发送到网络驱动程序上。


7.接收数据,调用recv函数

函数原型:ssize_t recv(int sockfd,void *buf, size_t len,int flags);

返回值:若函数调用成功,返回数据的字节长度;若无可用数据或等对等方已经按序结束,返回0;若出错,返回-1。

1)参数sockfd:接收端套接字描述符。

2)参数buf:指定缓冲区地址,用于存储接收数据。

3)参数len:指定的用于接收数据的缓冲区长度。

4)参数flag:调用执行方式,一般设该值为0。

recv先等待sock_fd的发送缓冲中的数据被协议传送完毕,如果协议在传送sock_fd的发送缓冲中的数据时出现网络错误,那么recv函数返回SOCKET_ERROR;如果sock_fd的发送缓冲中没有数据或者数据被协议成功发送完毕后,recv先检查套接字s的接收缓冲区,如果sock_fd接收缓冲区中没有数据或者协议正在接收数据,那么recv就一直等待,直到协议把数据接收完毕;当协议把数据接收完毕,recv函数就把sock_fd的接收缓冲中的数据copy到buf中(注意协议接收到的数据可能大于buf的长度,所以在这种情况下要调用几次recv函数才能把s的接收缓冲中的数据copy完。recv函数仅仅是copy数据,真正的接收数据是协议来完成的),recv函数返回其实际copy的字节数;如果recv在copy时出错,那么它返回SOCKET_ERROR;如果recv函数在等待协议接收数据时网络中断了,那么它返回0。


8.关闭套接字,调用close函数close缺省功能是将套接字作“已关闭”标记,并立即返回到调用进程,该套接字描述符不能再为该进程所用:即不能作为read和write(send和recv)的参数。


9.禁止一个套接字的I/O,调用shutdown

函数函数原型: int shutdown(int sockfd, int how);

返回值:若函数调用成功,返回0;若出错,返回-1。

1)参数sockfd:要操作的套接字。

2)参数how:可以是SHUT_RD(关闭读端),可以是SHUT_WR(关闭写端),也可以是SHUT_RDWR(既无法读数据也无法发数据)。

shutdown不仅可以灵活控制关闭连接的读、写或读写功能,而且会立即执行相应的断开动作(发送终止连接的FIN分节等),此时不论有多少进程共享此套接字描述符,都将不能再进行收发数据。



猜你喜欢

转载自blog.csdn.net/m0_38022615/article/details/80304787