做照片的网站,网站开发工程师优势,嵌入式培训机构排行,系统软件主要包括网页制作软件一、TCPTCP : 传输控制协议 传输层1. TCP特点(1).面向连接,避免部分数据丢失
(2).安全、可靠
(3).面向字节流
(4).占用资源开销大2.TCP安全可靠机制三次握手:指建立tcp连接时#xff0c;需要客户端和服务端总共发送三次报文确认连接。确保双方均已做好 收发…一、TCPTCP : 传输控制协议 传输层1. TCP特点(1).面向连接,避免部分数据丢失
(2).安全、可靠
(3).面向字节流
(4).占用资源开销大2.TCP安全可靠机制三次握手:指建立tcp连接时需要客户端和服务端总共发送三次报文确认连接。确保双方均已做好 收发数据的准备-----只能由客户端发起ACK:响应报文 SYN(TPC头部标志位)请求建立连接 FIN请求断开连接四次挥手断开一个tcp连接需要客户端和服务端发送四个报文以确认断开。确保断开连接前收 发数据均已完成 ,当服务端没有数据需要发送,即不需要建立下一次连接时,服务端将 ACK和FIN一起发送出去,即三次挥手. 三次挥手不能确认服务端每一次有无下一次连接.3.TCP注:服务端创建了两个套接字,recv里接接收的是第二个套接字(通信套接字)(1).socket socket(AF_INET, SOCK_STREAM, 0);(2).connect int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);功能:发送三次握手链接请求参数:sockfd:套接字文件描述符addr:存放目的地址空间首地址addrlen:目的地址长度返回值: 成功返回0 失败返回-1(3).send ssize_t send(int sockfd, const void *buf, size_t len, int flags);功能:发送数据参数:sockfd:套接字文件描述符buf:存放数据空间首地址len:数据长度flag:属性默认为0 返回值:成功返回发送字节数 ; 失败返回-1 (4).recv ssize_t recv(int sockfd, void *buf, size_t len, int flags);功能:接收数据 参数:sockfd:套接字文件描述符buf:存放数据空间首地址 len:最多接收数据长度 flags:接收属性默认为0 返回值:成功返回实际接收字节数 ; 失败返回-1 ; 连接断开返回0 (5).bindint bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);(6).listenint listen(int sockfd, int backlog);功能:监听三次握手链接请求参数:sockfd:套接字文件描述符backlog:最多允许等待尚未处理的三次握手链接个数返回值:成功返回0 ; 失败返回-1 (7).accept int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);功能:处理三次握手等待队列中的第一个请求并建立一个用来通信的新套接字参数:sockfd:套接字文件描述符addr:存放发送端IP地址空间首地址 addrlen:想要接收的IP地址的长度 返回值:成功返回新文件描述符(通讯套接字) ; 失败返回-1 4. TCP报文头标志位(1). URG 紧急指针标志 为1时表示紧急指针有效 该报文应该优先传送。
(2). ACK 确认应答标志
(3). PSH: 表示发送数据提示接收端从TCP接收缓冲区中读走数据为接收后续数据腾出空间
(4). RST 重置连接标志
(5). SYN 表示请求建立一个连接
(6). FIN finish标志 表示释放连接滑动窗口大小是TCP流量控制得一个手段。目的是告诉对方 本端得TCP接受缓冲区还能容纳 多少字节得数据
这样对方就可以控制发送数据的速度从而达到流量控制16bit2字节,因而窗口最大65535.5. TCP的机制TCP复杂是因为它既要保证可靠性同时又要尽可能的提高性能。可靠性
(1) 三次握手和四次挥手机制(2) 确认应答TCP将每个字节的数据都进行了编号即为序列号。每一个ACK都带有对应的确认 序列号保证数据不丢失的按序到达(3) 超时重传当发送端发送的数据在网络中丢失时在一定时间内没有收到接收端的ACK则发送端会重新发送丢失数据。(4)流量控制按照ACK中“窗口大小”字段控制发送端的发送速度提高性能1滑动窗口(缓冲区)可以按照“窗口大小” 一次发送多条后 再等待应答。
2延迟应答当接收方处理速度很快时可以延迟发送ACK此时窗口大小会自动增大
3捎带应答搭载应用层的响应报文发送ACK。 6. TCP粘包问题----面试题TCP协议是面向字节流的协议接收方不知道消息的界限不知道一次提取多少数据这就造成了粘包问题。粘包问题出现的原因 (接受发送速率不匹配)
(1). 发送端发送方发送数据过快造成粘包(2). 接收端不及时的接收缓冲区内的包造成多个包接收。接收过慢.避免粘包问题的方法(usleep())(1). 对于定长的包发送固定大小字节的数据,保证每次都按固定大小读取即可// 结构体 问题:1)结构体对齐问题(比如:指定按1字节对齐),不能放指针 2)发送数据类型多样化时,接收方难区分接受大小(2). 对于变长的包还可以在包和包之间使用明确的数据分隔符这个分隔符是由程序员自己来定的只要保证分隔符不和正文冲突即可。eg:hello world\n how are you\n xxxx\n应用层可以根据\n进行解析(3).自定义应用层的协议帧帧头: AA 1字节有效数据长度: len 1字节帧尾: BB 1字节校验:8bits和校验(1字节) 16bits和校验(2字节) CRC校验二、练习 1.使用tcp实现双人聊天
//cli.c
#include head.hint init_tcp_cli(const char *ip, unsigned short port)
{int sockfd socket(AF_INET, SOCK_STREAM, 0);if (sockfd 0){perror(fail socket);return -1;}struct sockaddr_in seraddr;seraddr.sin_family AF_INET;seraddr.sin_port htons(port);seraddr.sin_addr.s_addr inet_addr(ip);int ret connect(sockfd, (struct sockaddr *)seraddr, sizeof(seraddr));if (ret 0){perror(fail connect);return -1;}return sockfd;
}void *send_msg(void *arg)
{char buff[1024] {0};int sockfd *((int *)arg);while (1){memset(buff, 0, sizeof(buff));fgets(buff ,sizeof(buff), stdin);send(sockfd, buff, strlen(buff), 0);}return NULL;
}void *recv_msg(void *arg)
{char buff[1024] {0};int sockfd *((int *)arg);while (1){memset(buff, 0, sizeof(buff));ssize_t size recv(sockfd, buff, sizeof(buff), 0);if (size 0){perror(fail recv);break;}else if (0 size){printf(connect lost\n);break;}printf(B--A: %s\n, buff);}return NULL;
}int main(int argc, const char *argv[])
{pthread_t tid[2];int sockfd init_tcp_cli(192.168.1.162, 50000);if (sockfd 0){return -1;}pthread_create(tid[0], NULL, send_msg, sockfd);pthread_create(tid[1], NULL, recv_msg, sockfd);pthread_join(tid[0], NULL);pthread_join(tid[1], NULL);close(sockfd);return 0;
}
//ser.c
#include head.hint init_tcp_ser(const char *ip, unsigned short port)
{int sockfd socket(AF_INET, SOCK_STREAM, 0);if (sockfd 0){perror(fail socket);return -1;}struct sockaddr_in seraddr;seraddr.sin_family AF_INET;seraddr.sin_port htons(port);seraddr.sin_addr.s_addr inet_addr(ip);int ret bind(sockfd, (struct sockaddr *)seraddr, sizeof(seraddr));if (ret 0){perror(fail bind);return -1;}ret listen(sockfd, 10);if (ret 0){perror(fail listen);return -1;}return sockfd;
}void *send_msg(void *arg)
{char buff[1024] {0};int sockfd *((int *)arg);while (1){memset(buff, 0, sizeof(buff));fgets(buff ,sizeof(buff), stdin);send(sockfd, buff, strlen(buff), 0);}return NULL;
}void *recv_msg(void *arg)
{char buff[1024] {0};int connfd *((int *)arg);while (1){memset(buff, 0, sizeof(buff));ssize_t size recv(connfd, buff, sizeof(buff), 0);if (size 0){perror(fail recv);break;}else if (0 size){printf(connect lost\n);break;}printf(A--B: %s\n, buff);}return NULL;
}int main(int argc, const char *argv[])
{pthread_t tid[2];int sockfd init_tcp_ser(192.168.1.162, 50000);if (sockfd 0){return -1;}int connfd accept(sockfd, NULL, NULL);if (connfd 0){perror(fail accpet);return -1;}pthread_create(tid[0], NULL, send_msg, connfd);pthread_create(tid[1], NULL, recv_msg, connfd);pthread_join(tid[0], NULL);pthread_join(tid[1], NULL);close(connfd);close(sockfd);return 0;
}
#ifndef __HEAD_H__
#define __HEAD_H__#include stdio.h
#include sys/types.h /* See NOTES */
#include sys/socket.h
#include netinet/in.h
#include netinet/ip.h /* superset of previous */
#include arpa/inet.h
#include unistd.h
#include string.h
#include pthread.h#endif 2.使用tcp实现文件发送
//cli.c
#include head.hint init_tcp_cli(const char *ip, unsigned short port)
{int sockfd socket(AF_INET, SOCK_STREAM, 0);if (sockfd 0){perror(fail socket);return -1;}struct sockaddr_in seraddr;seraddr.sin_family AF_INET;seraddr.sin_port htons(port);seraddr.sin_addr.s_addr inet_addr(ip);int ret connect(sockfd, (struct sockaddr *)seraddr, sizeof(seraddr));if (ret 0){perror(fail connect);return -1;}return sockfd;
}int send_file(int sockfd, const char *filename)
{send(sockfd, filename, strlen(filename), 0);usleep(10);int fd open(filename, O_RDONLY);if (fd 0){perror(fail open);return -1;}char buff[1024] {0};while (1){ssize_t size read(fd, buff, sizeof(buff));if (size 0){break;}send(sockfd, buff, size, 0);}close(fd);return 0;
}int main(int argc, const char *argv[])
{int sockfd init_tcp_cli(192.168.1.162, 50000);if (sockfd 0){return -1;}send_file(sockfd, 1.jpg);close(sockfd);return 0;
}
//ser.c
#include head.hint init_tcp_ser(const char *ip, unsigned short port)
{int sockfd socket(AF_INET, SOCK_STREAM, 0);if (sockfd 0){perror(fail socket);return -1;}struct sockaddr_in seraddr;seraddr.sin_family AF_INET;seraddr.sin_port htons(port);seraddr.sin_addr.s_addr inet_addr(ip);int ret bind(sockfd, (struct sockaddr *)seraddr, sizeof(seraddr));if (ret 0){perror(fail bind);return -1;}ret listen(sockfd, 10);if (ret 0){perror(fail listen);return -1;}return sockfd;
}int recv_file(int connfd)
{char buff[1024] {0};char fileneme[1024] {0};recv(connfd, fileneme, sizeof(fileneme), 0);printf(fileneme %s\n, fileneme);int fd open(fileneme, O_WRONLY | O_CREAT | O_TRUNC, 0664);if (fd 0){perror(fail open);return -1;}while (1){ssize_t size recv(connfd, buff, sizeof(buff), 0);if (size 0){break;}write(fd, buff, size);}close(fd);return 0;
}int main(int argc, const char *argv[])
{int sockfd init_tcp_ser(192.168.1.162, 50000);if (sockfd 0){return -1;}int connfd accept(sockfd, NULL, NULL);if (connfd 0){perror(fail accpet);return -1;}recv_file(connfd);close(connfd);close(sockfd);return 0;
}