Linux TCP协议的基础编程模型

一、TCP协议的基础编程模型

TCP是面向连接的通信协议,采用客户机-服务器模式。套接字的全部工作流程如下所述:

1.服务器启动进程,调用Socket创建一个基于TCP协议的流套接字描述符。

2.其次,服务进程调用bind命名套接字,将套接字描述符绑定到本地地址和本地端口上,至此Socket的半相关描述---{协议,本地地址,本地端口}---完成。

3.再次,服务器端调用listen,开始侦听客户端的Socket连接请求。

4.接下来,客户端创建套接字描述符,并且调用connect向服务端提交连接请求。服务器端接收到客户端连接请求后,调用accept接受,并创建一个新的套接字描述符与客户端建立连接,然后原套接字描述符继续侦听客户端的连接请求。

5.客户端与服务器端的新套接字进行数据传送,调用write或send向对方发送数据,调用read或recv接收数据。

6.在数据交流完毕后,双方调用close或者shutdown半闭套接字。
 

二、UNIX基于TCP的通信相关函数

1.Socket的创建---系统调用Socket

       #include<sys/types.h>

       #include<sys/socket.h>

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

       返回值:成功返回创建的套接字描述符,否则返回-1并置errno。

       说明:函数socket创建一个Socket描述符。

       domain 指定发送通信的域,即套接字的协议族。有AF_UNIX(本地主机通信)和AF_INET(Internet地址IPV4协议)。

       type 指定通信类型,有SOCK_STREAM,SOCK_DGRAM和SOCK_RAW。

       Protocol指定了该套接字描述符上的一个特殊的协议书,比如TCP、UDP等,一般设置为0。

2.Socket的命名---系统调用bind

       #include<sys/types.h>

       #include<sys/socket.h>

       int bind(int s, const struct sockaddr *name, int namelen);

       返回值:成功返回0,否则返回-1并置errno。

       函数bind命名一个套接字,它为该套接字描述符分配一个半相关属性。

       s 调用socket创建的套接字。

       指针name指向通用套接字的协议地址结构,包括协议、地址和端口信息等。

       namelen 指定该协议地址结构长度,一般定义为sizeof(sockaddr_in)。

       关于套接字地址属性结构:

       struct  sockaddr{

              u_short   sa_family;      /* 协议族 */

              char        sa_data[14];    /* 最多14字节的协议地址 */

       };

       不同的协议有不同的地址描述方式,为了便于编码处理,每种协议族都定义了自己的套接字地址属性结构,比如协议族AF_INET使用结构sockaddr_in描述套接字地址信息,该结构定义在头文件<netinet/in.h>中。

       struct sockaddr_in{

              short       sin_family;      /* 16位的地址协议族(AF_INET)*/

              u_short   sin_port;         /* 16位的端口地址 */

              struct in_addr sin_addr; /* 32位的IP地址 */

              char        sin_zero[8];    /* 预留 */

       };

       struct in_addr{

              u_long     s_addr;

       };

       预留成员作用是使结构sockaddr_in与结构sockaddr的长度相同。

       IP地址转换---完成IP地址的字符串格式与32位4字节整型之间的转换。

       unsigned  long  inet_addr(char *ptr);

       int   inet_aton(char *ptr, stuct in_addr *addrptr);

       char  *inet_ntoa(struct  in_addr inaddr);

       字节顺序转换---实现主机字节顺序与网络字节顺序之间转换

       #include<sys/types.h>

       #include<netinet/in.h>

       u_short htons(u_short hostshort); /*将16位整数由主机字节顺序转换成网络字节顺序*/

       u_long htonl(u_long hostlong);      /*将32位整数由主机字节顺序转换成网络字节顺序*/    u_short ntohs(u_short netshort);       /*将16位整数由网络字节顺序转换成主机字节顺序*/

       u_long ntohl(u_long netlong);       /*将32位整数由网络字节顺序转换成主机字节顺序*/

       例:命名套接字描述符s的协议为AF_INET,地址为“127.0.0.1”,端口号为1000。

       struct sockaddr_in sockaddr1;      /*申请地址结构空间*/

       memset(&sockaddr1, 0 , sizeof(sockaddr1));             /*清空空间*/

       sockaddr1.sin_family = AF_INET;

       sockaddr1.sin_addr.s_addr = inet_addr(“127.0.0.1”);  /*IP地址转换为整型赋值*/

       sockaddr1.sin_port = htons(1000);              /*端口号 主机字节顺序转换为网络字节顺序*/

       如需系统自动指定套接字的IP地址,则

       sockaddr1.sin_addr.s_addr = htonl(INADDR_ANY);   /*自动分配地址*/

3.Socket的侦听---系统调用listen

       #include<sys/types.h>

       #include<sys/socket.h>

       int listen(int s, int backlog);

       返回值:成功返回0,否则返回-1并置errno。

       TCP服务器端必须调用listen函数才能使套接字进入侦听状态。

       s 调用socket创建、bind命名的套接字。

       backlog 确定套接字s接收的最大数目,如果到达最大的连接数,服务器端将向客户端发出ECONNRERUSED错误。

相关推荐