提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
一、tcp
1.TCP基本概念及特点
传输控制协议:
特点:
(1)有链接
(2)可靠传输方式,应答机制,重传机制
(3)流式套接字
(流:数据有方向。发的顺序和收到顺序是一样的。数据是连续的。
写:有阻塞,写满64K会阻塞)
(4)全双工工作方式(有两个缓冲区(64K),在内核中存放)
(5)数据之间没有边界会出现粘包,解决的办法有(1)固定的结束方式,(2)固定大小传送数据,使用结构体传送数据。
(1)有链接
客户端服务器在链接之后,网络链路不会发生改变。
(3)流式套接字
全双工的工作方式:有两个64k的缓存区,一方负责收,一方负责发
写端带有阻塞功能。
2.tcp通讯过程
监听套接字:监听有没有人来链接服务器。
通讯套接字:用来收发数据的套接字。
1.三次握手
1.三次握手目的为了建立链接,后续进行正常的通讯
2.过程
(1)客户端向服务器发送SYN
(2)服务器向客户端ACK(应答机制是SYN数值加1)和SYN
(4)客户端给服务器发送ACK(是服务器发送SYN加1)
2.四次挥手
1.四次挥手
2.过程
(1)客户端向服务器发送FIN
(2)服务器向客户端ACK(应答机制是FIN数值加1)
(3)服务器向客户端FIN和ACK
(4)客户端给服务器发送ACK(是服务器发送FIN加1)
3.TCP编程步骤
3.TCP函数接口
1.创建套接字
int socket(int domain, int type, int protocol);
功能:
创建用于交流的套接字文件
参数:
domain:ip协议是IPV4还是ipv6
type:是用
TCP:SOCK_STREAM
UDP:SOCK_DGRAM
protocol
返回值:
成功返回0
失败返回-1
2.绑定套接字
int bind(int sockfd, const struct sockaddr *addr,
socklen_t addrlen);
功能:将地址绑定在套接字文件上
参数:
sockfd:套接字
const struct sockaddr *addr:地址变量结构体,因为网络设备均为大端,需要将端口号和IP转换为大端,
struct sockaddr 通用地址结构
{
u_short sa_family; 地址族
char sa_data[14]; 地址信息
};
在man 7 ip中查网络地址结构
转换成网络地址结构如下:
struct _sockaddr_in ///网络地址结构
{
u_short sin_family; 地址族
u_short sin_port; ///地址端口
struct in_addr sin_addr; ///地址IP
char sin_zero[8]; 占位
};
端口小端转大端:
uint16_t htons(uint16_t hostshort);
端口大端转小端:
uint16_t ntohs(uint16_t netshort);
主机转网络:ip小端转大端:
网络转主机:
in_addr_t inet_addr(const char *cp);
网络转主机:ip大端转小端:
char *inet_ntoa(struct in_addr in);
addrlen:地址的大小
返回值:
成功返回0
失败返回-1
3.int listen(int sockfd, int backlog);
功能:设置套接字为监听套接字
参数:
sockfd:设置的套接字
backlog:同一时刻监听套接字的最大排队数
返回值:
成功返回0
失败返回-1
4.int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
三次握手的函数
功能:设置监听套接字为通讯套接字
参数:
sockfd:设置的监听套接字
addr:客户端的地址结构体
addrlen:客户端的地址结构体的大小
返回值:
成功返回值为通讯套接字
失败返回-1
5.收发:
因为tcp是链接固定的所以不需要发地址
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
功能:
接收用于通讯套接字的数据
参数:
sockfd:接收的套接字
buf:数据通过buf传递过来
len:buf的大小
flags:传递的方式一般用0就可以
返回值
大于0返回读到的字节数
等于0通讯断开
小于0链接出现错误
6.ssize_t send(int sockfd, const void *buf, size_t len, int flags);
功能:向套接字发送数据
sockfd:接收的套接字
buf:数据通过buf传递过来
len:buf的大小
flags:传递的方式一般用0就可以
返回值:
大于0发送数据的字节数
等于0数据没有发送出去
小于0发送失败
7.int connect(int sockfd, const struct sockaddr *addr,
socklen_t addrlen)
功能:用于客户端链接服务器
参数:
sockfd:设置的监听套接字
addr:客户端的地址结构体
addrlen:客户端的地址结构体的大小
返回值:
成功返回0
失败返回-1
3.TCP错误
1.bind:地址被占用
原因:两个端口被重复使用,或者已经结束的程序是异常结束,没有触发四次挥手套接字没有释放。
解决的办法是在服务端的listen前面调用 :
int on = 1;
int setsockopt(int sockfd, int level, int optname,
const void *optval, socklen_t optlen);
调用示例:
setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));
只能在测试场景中使用,在真正的应用场景无法使用。