Linux学习之网络编程(TCP编程 模型总结)

言之者无罪,闻之者足以戒。 - “诗序”

TCP通信也就是服务器和客户端的一种通信方式,它的整体框架为:

针对TCP通信所用到的函数,我来做一下说明:

(1)插座创造一个套接字

int socket(int domain,int type,int protocol)

头文件的:#include <SYS / socket.h>中

第一个参数:通信域,确定通信特性,包括地址格式域描述

第二个参数:套接字类型

第三个参数:指定相应的传输协议

返回值:成功则返回套接字文件描述符,失败返回-1

参数域:通信域,确定通信特性,包括地址格式域描述
参数协议:指定相应的传输协议,也就是诸如TCP或UDP协议等等,系统针对每一个协议簇与类型提供了一个默认的协议,我们通过把协议设置为0来使用这个默认的值。

family:     type:       组合      AF_INET AF_INET6 AF_LOCAL AF_PACKET
解释     SOCK_STREAM 字节   流套接字   TCP TCP YES  
AF_INET IPv4协议   SOCK_DGRAM 数据包套接字   UDP UDP YES  
AF_INET6 IPv6协议   SOCK_RAM 原始套接字   IPv4 IPv6   ethernet
AF_LOCAL/AF_UNIX 本地套接字                
AF_PACKET                  

(2)建立与TCP服务器的连接 

int   connect(int sockfd, const  struct  sockaddr  *servaddr, socklen_t  addrlen)

第一个参数:是由socket函数返回的套接字描述符

第二个参数:指向套接字地址结构的指针

第三个参数:地址结构的大小

套接字地址结构必须包含有服务器的IP地址和端口号

返回值:成功返回0,出错返回-1

客户在调用connect之前不必非得调用bind函数,因为如果需要的话,内核会确定源IP地址并选择一个临时端口作为端口号

如果是TCP套接字,调用connect函数将激发TCP的三次握手过程,而且仅在连接建立成功或出错时才返回,其中,出错返回的可能情况有以下几种:

1)若TCP客户没有收到SYN分节的响应,则返回ETIMEDOUT错误。举例,调用connect函数时,4.4BSD内核发送一个SYN,若无响应则等待6s后再发送一个,若仍无响应则等待24s后再发送一个。若总共等待了75s后仍未收到响应则返回本错误

2)若对客户的SYN的响应是RST(表示复位),则表明该服务器主机在我们指定的端口上没有进程在等待与之连接。这是一种硬错误,客户一收到RST就马上返回ECONNREFUSED错误。

3)若客户发出的SYN在中间的某个路由器上引发了一个“destination unreachable”(目的地不可达)ICMP错误,则认为是一个软错误。客户主机内核保存该消息,并按第一种情况所述的时间间隔继续发送SYN。若在某个规定的时间内仍无响应,则把保存的信息(即ICMP错误)作为EHOSTUNREACH或ENETUNREACH错误返回给进程。以下两种情况是有可能的:一是按照本地系统的转发表,根本没有到达远程系统的路径;二是connect调用根本不等待就返回。

(3)结合绑定服务器的地址和端口到插座

这样做就是让客户端来发现用以连接的服务器的地址

int bind(int sockfd,const struct sockaddr * addr,socklen_t len)

头文件:#include <sys / socket.h>

第一个参数:是由socket函数返回的套接字描述符

第二个参数:服务器的地址

第三个参数:地址的长度

返回值:成功返回0,失败返回-1
参数地址:服务器的地址,对于因特网域,如果设置地址为INADDR_ANY,套接字可以绑定到所有的网络端口。这意味着可以收到这个系统所有网卡的数据包。一般我们,在使用SOCKADDR_IN类型的结构体代替的sockaddr行业释义体系结构
参数len:指定地址的长度

下面罗列一下常见的几种出错情况:

1)IP地址可以选择通配地址,端口号为0表示(内核分配临时端口)

2)INADDR_ANY,由内核选择IP接口,这个宏的值为0(注意:该宏对于IPv4是可行的)

3)分配临时端口号,需要用函数getsockname,来返回 你的协议地址

4)绑定通常会返回的错误:Address  already  in  use ,通过套接字选项来设置,setsockopt,SO_REUSEADDR

(4)设置允许的最大连接数

int listen(int sockfd,int backlog)

头文件:#include <sys / socket.h>

第一个参数:是由socket函数返回的套接字描述符

第二个参数:用于表示服务器能接受的请求数量

返回值:成功返回0,失败返回-1

服务器调用监听函数来宣告可以接受连接请求

关于listen函数的相关内容可以参考https://www.cnblogs.com/lengender-12/p/6813057.html

(5)接受等待来自客户端的连接请求

int accept(int sockfd,struct sockaddr * restrict addr,socklen_t * restrict len)

头文件的:#include <SYS / socket.h>中

第一个参数:是由socket函数返回的套接字描述符

第二个参数:用来存放客户端的地址,如果地址的空间足够大,系统会自动填充。

第三个参数:地址的长度

返回值:成功则返回套接字描述符,失败返回-1

一旦服务器调用了听,套接字就能接收连接请求。使用接受函数来接受并建立请求

 注意:
1,接受返回一个新的socket关联到客户端,它与原始的socket有相同的套接字类型和协议族。传递给接受的原始socket并没有关联客户端,它要继续保持可用状态,接收其他请求。
2,接受是一个阻塞的函数,会一直等到有客户端的请求。

猜你喜欢

转载自blog.csdn.net/weixin_42994525/article/details/83537772
今日推荐