山东省建设部网站官网,丰南建设局网站,网站用户体验分析怎么做,网站代码修改1 TCP协议
1.1 概念
TCP是一种面向连接的、可靠的协议#xff0c;有点像打电话#xff0c;双方拿起电话互通身份之后就建立了连接#xff0c;然后说话就行了#xff0c;这边说的话那边保证听得到#xff0c;并且是按说话的顺序听到的#xff0c;说完话挂机断开连接。也…1 TCP协议
1.1 概念
TCP是一种面向连接的、可靠的协议有点像打电话双方拿起电话互通身份之后就建立了连接然后说话就行了这边说的话那边保证听得到并且是按说话的顺序听到的说完话挂机断开连接。也就是说TCP传输的双方需要首先建立连接之后由TCP协议保证数据收发的可靠性丢失的数据包自动重发上层应用程序收到的总是可靠的数据流通讯之后关闭连接。
1.2 TCP数据包格式 1.3 TCP3次握手过程 1.3.1 客户端发送一个带SYN标志的TCP报文到服务器。这是三次握手过程中的段1
客户端发出段1SYN位表示连接请求。序号是1000这个序号在网络通讯中用作临时的地址每发一个数据字节这个序号要加1这样在接收端可以根据序号排出数据包的正确顺序也可以发现丢包的情况另外规定SYN位和FIN位也要占一个序号这次虽然没发数据但是由于发了SYN位因此下次再发送应该用序号1001。mss表示最大段尺寸如果一个段太大封装成帧后超过了链路层的最大帧长度就必须在IP层分片为了避免这种情况客户端声明自己的最大段尺寸建议服务器端发来的段不要超过这个长度。
1.3.2 服务器端回应客户端是三次握手中的第2个报文段同时带ACK标志和SYN标志。它表示对刚才客户端SYN的回应同时又发送SYN给客户端询问客户端是否准备好进行数据通讯。
服务器发出段2也带有SYN位同时置ACK位表示确认确认序号是1001表示“我接收到序号1000及其以前所有的段请你下次发送序号为1001的段”也就是应答了客户端的连接请求同时也给客户端发出一个连接请求同时声明最大尺寸为1024。
1.3.3 客户必须再次回应服务器端一个ACK报文这是报文段3。
客户端发出段3对服务器的连接请求进行应答确认序号是8001。在这个过程中客户端和服务器分别给对方发了连接请求也应答了对方的连接请求其中服务器的请求和应答在一个段中发出因此一共有三个段用于建立连接称为“三方握手three-way-handshake”。在建立连接的同时双方协商了一些信息例如双方发送序号的初始值、最大段尺寸等。
在TCP通讯中如果一方收到另一方发来的段读出其中的目的端口号发现本机并没有任何进程使用这个端口就会应答一个包含RST位的段给另一方。例如服务器并没有任何进程使用8080端口我们却用telnet客户端去连接它服务器收到客户端发来的SYN段就会应答一个RST段客户端的telnet程序收到RST段后报告错误Connection refused
1.4 数据传输 客户端发出段4包含从序号1001开始的20个字节数据。服务器发出段5确认序号为1021对序号为1001-1020的数据表示确认收到同时请求发送序号1021开始的数据服务器在应答的同时也向客户端发送从序号8001开始的10个字节数据这称为piggyback。客户端发出段6对服务器发来的序号为8001-8010的数据表示确认收到请求发送序号8011开始的数据。
在数据传输过程中ACK和确认序号是非常重要的应用程序交给TCP协议发送的数据会暂存在TCP层的发送缓冲区中发出数据包给对方之后只有收到对方应答的ACK段才知道该数据包确实发到了对方可以从发送缓冲区中释放掉了如果因为网络故障丢失了数据包或者丢失了对方发回的ACK段经过等待超时后TCP协议自动将发送缓冲区中的数据包重发。
1.5 TCP4次挥手 由于TCP连接是全双工的因此每个方向都必须单独进行关闭。这原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接。收到一个 FIN只意味着这一方向上没有数据流动一个TCP连接在收到一个FIN后仍能发送数据。首先进行关闭的一方将执行主动关闭而另一方执行被动关闭。 客户端发出段7FIN位表示关闭连接的请求。 服务器发出段8应答客户端的关闭连接请求。 服务器发出段9其中也包含FIN位向客户端发送关闭连接请求。 客户端发出段10应答服务器的关闭连接请求。
建立连接的过程是三方握手而关闭连接通常需要4个段服务器的应答和关闭连接请求通常不合并在一个段中因为有连接半关闭的情况这种情况下客户端关闭连接之后就不能再发送数据给服务器了但是服务器还可以发送数据给客户端直到服务器也关闭连接为止。
2 案例
2.1 SERVER端
#includesys/socket.h
#includearpa/inet.h
#include stdio.h
#include ctype.h
#include sys/socket.h
#include arpa/inet.h
#include stdlib.h
#include unistd.h
#include errno.h#define SERV_PORT 9527
void sys_err(const char *str){perror(str);exit(1);
}
int main(int argc,char *argv[]){// 定义监听套接字、通信套接字int lfd 0, cfd 0;int ret,i;char buf[BUFSIZ],client_IP[1024];// 定义服务器端、客户端地址结构struct sockaddr_in serv_addr,clit_addr;// 客户端地址结构长度socklen_t clit_addr_len;// 初始化服务器端地址结构serv_addr.sin_family AF_INET;serv_addr.sin_port htons(SERV_PORT);serv_addr.sin_addr.s_addr htonl(INADDR_ANY);// 监听套接字初始化以及创建失败处理lfd socket(AF_INET,SOCK_STREAM,0);if(lfd -1) {sys_err(socket error);}// 将套接字绑定IP端口bind(lfd,(struct sockaddr *)serv_addr, sizeof(serv_addr));// 设置lfd套接字用于监听以及可以连接的客户端套接字数量listen(lfd,128);// 客户端地址结构长度初始化clit_addr_len sizeof(clit_addr);// 本服务器端目前只可同时对一个客户端进行通信while(1){// 设置服务端套接字为被动状态返回一个新的套接字用于通信以及创建失败处理cfd accept(lfd, (struct sockaddr *)clit_addr, clit_addr_len);if(cfd -1){sys_err(accept error);}// 打印客户端ip以及端口printf(client ip: %s port:%d\n, inet_ntop(AF_INET,clit_addr.sin_addr.s_addr,client_IP,sizeof(client_IP)),ntohs(clit_addr.sin_port));while(1) {// 接收客户端传来的数据ret read(cfd,buf,sizeof(buf));if(ret 0) {printf(the link is disconneted!\n);break;}// 将客户端数据传入标准输出流中write(STDOUT_FILENO,buf,ret);// 将传来的数据变大写并传回到客户端for(i 0; i ret; i)buf[i] toupper(buf[i]);write(cfd,buf,ret);}}// close(lfd);// close(cfd);return 0;
}
2.2 CLIENT端
客户端得知服务器端ip以及端口即可通信
#include stdio.h
#include sys/socket.h
#include arpa/inet.h
#include stdlib.h
#include string.h
#include unistd.h
#include errno.h
#include pthread.h#define SERV_PORT 9527void sys_err(const char *str)
{perror(str);exit(1);
}int main(int argc, char *argv[])
{int cfd;int conter 10;char buf[BUFSIZ];//服务器地址结构struct sockaddr_in serv_addr; serv_addr.sin_family AF_INET;serv_addr.sin_port htons(SERV_PORT);// 转换ip地址由点分制到二进制inet_pton(AF_INET, 127.0.0.1, serv_addr.sin_addr);// 初始化用于通信的套接字cfd socket(AF_INET, SOCK_STREAM, 0);if (cfd -1)sys_err(socket error);// 将客户端套接字与服务器端套接字连接int ret connect(cfd, (struct sockaddr *)serv_addr, sizeof(serv_addr));if (ret ! 0)sys_err(connect err);while (--conter) {// 将数据通过套接字传输给服务器端write(cfd, hello\n, 6);// 从套接字读取数据ret read(cfd, buf, sizeof(buf));// 将数据输出至标准输出write(STDOUT_FILENO, buf, ret);sleep(1);}// 关闭客户端套接字close(cfd);return 0;
}
2.3 实现效果
运行服务器端服务器先阻塞等待客户端请求运行客户端客户端发送连接请求连接成功服务器端输出客户端ip以及端口服务器获取客户端传来的数据并将其打印到标准输出以及对其进行大写转换服务器将处理好的数据发送给客户端客户端获取数据并打印至标准输出客户端关闭套接字
客户端 服务器端
3 通信时序与代码对应图