TCP通信:
1. TCP发端:
socket -> connect -> send -> recv -> close
2. TCP收端:
socket -> bind -> listen -> accept -> recv -> send -> close
3. TCP需要用到的函数:
1. connect:
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
功能:发送链接请求
参数:
sockfd:套接字文件描述符
addr:目的地址存放空间首地址
addrlen:IP地址的大小
返回值:
成功返回0
失败返回-1
2. send:
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
功能:发送数据
参数:
sockfd:文件描述符
buf:发送数据空间首地址
flags:属性默认为0
返回值:
成功返回实际发送字节数
失败返回-1
3. recv:
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
功能:接收数据
参数:
sockfd:套接字文件描述符
buf:存放数据空间首地址
len:最大接收数据的长度
flags:属性,默认为0
返回值:
成功返回实际接收字节数
失败返回-1
如果对方退出,返回0
4. listen:
int listen(int sockfd, int backlog);
功能:监听客户端发送的连接请求(该函数不会阻塞)
参数:
sockfd:套接字文件描述符
backlog:允许等待的尚未被处理的三次握手请求的最大个数
返回值:
成功返回0
失败返回-1
5. accept:
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
功能:处理等待连接队列中的第一个连接请求,该函数具有阻塞功能(如果没有人发送链接请求,会阻塞等待)
参数:
socket:套接字文件描述符
address:存放IP地址的空间首地址
addrlen:存放IP地址大小空间首地址
返回值:
成功返回一个新的文件描述符
失败返回-1
4. TCP编程练习:
1. 利用TCP实现跨主机的文件发送:
send.c
#include "head.h"int main(void)
{FILE *fd = NULL;int sockfd = 0;int ret = 0;struct sockaddr_in severaddr;ssize_t nsize = 0;size_t rret = 0;char filename[100] = {0};char tmpbuff[1024] = {0};sockfd = socket(AF_INET, SOCK_STREAM, 0);if(sockfd == -1){perror("fail to socket");return -1;}severaddr.sin_family = AF_INET;severaddr.sin_port = htons(50000);severaddr.sin_addr.s_addr = inet_addr("192.168.1.162");ret = connect(sockfd,(struct sockaddr *)&severaddr, sizeof(severaddr));if(ret == -1){perror("fail to connect");return -1;}scanf("%s", filename);fd = fopen(filename, "r");if(fd == NULL){perror("fail to fopen");return -1;}nsize = send(sockfd, filename, strlen(filename), 0);if(nsize == -1){perror("fail to send");return -1;}while(1){memset(tmpbuff, 0, sizeof(tmpbuff));rret = fread(tmpbuff, 1, sizeof(tmpbuff), fd);if(rret == 0){break;}usleep(1000);nsize = send(sockfd, tmpbuff, rret, 0);if(nsize == -1){perror("fail to send");return -1;}}fclose(fd);close(sockfd);return 0;}
在这里,nsize = send(sockfd, tmpbuff, rret, 0);中,必须使用rret作为发送的字节大小,不能用strlen(tmpbuff),因为如果是二进制文件,不是ASCII码文件,\0可能成为发送的内容,所以在这里rret作为读到的字节数,可以直接作为send的输入。
其中在进行接收数据的时候,usleep(1000),是防止在TCP传输时出现的粘包现象,如果没有这段代码,那么接收端,接收的文件就会出现:内容和名字共同作为接收方所收到文件的文件名。为了防止这种粘包的情况,我们还可以在传输数据的时候,给数据加上帧头和帧尾,将文件名和数据内容分隔开。
recv.c
#include "head.h"int main(void)
{FILE *fd = NULL;int ret = 0;int sockfd = 0;int contfd = 0;ssize_t nsize = 0;char *ptmp = NULL;char tmpbuff[1024] = {0};struct sockaddr_in serveraddr;serveraddr.sin_family = AF_INET;serveraddr.sin_port = htons(50000);serveraddr.sin_addr.s_addr = INADDR_ANY;sockfd = socket(AF_INET, SOCK_STREAM, 0);if(sockfd == -1){perror("fail to socket");return -1;}ret = bind(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));if(ret == -1){perror("fail to ret");return -1;}ret = listen(sockfd, 10);if(ret == -1){perror("fail to listen");return -1;}contfd = accept(sockfd, NULL, NULL);if(contfd == -1){perror("fail to accept");return -1;}nsize = recv(contfd, tmpbuff, sizeof(tmpbuff), 0);if(nsize == -1){perror("fail to recv");return -1;}fd = fopen(tmpbuff, "w");if(fd == NULL){perror("fail to fopen");return -1;}while(1){memset(tmpbuff, 0, sizeof(tmpbuff));nsize = recv(contfd, tmpbuff, sizeof(tmpbuff), 0);if(nsize <= 0){break;}fwrite(tmpbuff, 1, nsize, fd);}fclose(fd);close(contfd);close(sockfd);return 0;
}
5. TCP包头:
1. 序号:发送端发送数据的编号
2. 确认号:已经确认接收到的数据的编号(只有当ACK为1时,确认好才有用)
3. 第四行为首部长度:数据前面的称之为头部,6位标记位,每一个标记位占一位
URG:紧急标志位 ACK:确认标记位 RST:断开连接标记位
SYN:请求标记位,置1建立连接的过程
FIN:结束标记位,置1释放连接的过程
PSH:若置为1这一数据段不在缓存区里等待,直接优先处理
4. 校验和:目的是保证数据完整性
5. 注意:不要将确认序号Ack与标志位ACK搞混了,确认方Ack=发起方Seq+1,两端配对
6. TCP为什么安全可靠:
1. 在通信前建立三次握手连接:SYN、SYN+ACK、ACK
2. 在通信过程中通过序列号和确认号保障数据传输的完整性
本次发送序列号:上次收到的确认号
本次发送确认号:上次接收到的序列号+实际接收的数据长度
3. 在通信结束时使用四次挥手连接保障数据传输的完整性
7. UDP和TCP的区别:
1. UDP和TCP都是传输层的协议
2. UDP实现机制简单,资源开销小,不安全不可靠
3. TCP实现机制复杂,资源开销大,安全可靠
4. UDP是无连接、TCP有连接、UDP是以数据包形式传输、TCP是以流的方式传输
HTTP协议:
1.URL:
代表着是统一资源定位符,每个有效的 URL 都指向一个唯一的资源。这个资源可以是一个 HTML 页面等等。
<协议>://<主机>:<端口>/<路径>
协议 :HTTP :80 TCP
协议 :HTTPS :443 TCP
主机:域名 -> 域名解析服务器 -> IP地址
端口:可以省,HTTP 80, HTTPS 443
路径:想要获得对应的资源
2. HTTP交互过程:
1. 建立TCP连接
2. 发送HTTP请求报文
3. 回复HTTP请求报文
4. 关闭TCP连接