tcp 协议基本信息:

选项子段:(tcp/ip : p192)

  • 选项表结束:
  • 无操作:
  • 最大报文长度
  • 窗口扩大因子:

TCP连接的建立与中止:

– – 连接的建立:

22:22:46.510758 IP (tos 0x0, ttl 64, id 29789, offset 0, flags [DF], proto TCP (6), length 60)192.168.1.86.56132 > 192.168.1.80.8068: Flags [S], cksum 0x8425 (incorrect -> 0xdf97), seq 4036226398, win 29200, options [mss 1460,sackOK,TS val 10656003 ecr 0,nop,wscale 7], length 0
22:22:46.511781 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto TCP (6), length 60)192.168.1.80.8068 > 192.168.1.86.56132: Flags [S.], cksum 0x1ac4 (correct), seq 519747379, ack 4036226399, win 14480, options [mss 1460,sackOK,TS val 3745757 ecr 10656003,nop,wscale 6], length 0
22:22:46.511843 IP (tos 0x0, ttl 64, id 29790, offset 0, flags [DF], proto TCP (6), length 52)192.168.1.86.56132 > 192.168.1.80.8068: Flags [.], cksum 0x841d (incorrect -> 0x8139), seq 1, ack 1, win 229, options [nop,nop,TS val 10656004 ecr 3745757], length 0
  • 最大报文长度:

    • 当一个连接建立是, 双方告知双方的 MSS 来协商最大窗口选项
  • 连接请求队列:

    • 等待连接的一段有一个固定长度的连接队列, 该队列中的连接已被TCP接受,但还没有被应用层所接受。
    • 应用层只有在三次握手重第三个报文段受到后才会知道这个新的连接,
    • 如果对于新的连接,连接队列中没有空间,TCP将不理会受到的SYN,也不发送任何报文段
    • 当用户层接受一个连接时, 他将从队列中移出;

    说明:
    TCP 服务器无法使客户进程的主动打开失效。当一个新的客户连接传递给服务器的应用程序时,TCP的 三次握手链接已经结束

  • Nagle 算法:

    • 该算法应对小分组增加拥赛出现的问题
    • 该算法要求一个TCP链接上最多只能有一个未被确认的未完成的小分组,该分组的确认到达之前不能发送其他的的小分组,相反, TCP收集这些少量的分组,并在确认到来时以一个分组的方式发出去;
  • RTT 的計算
    ERR = M – A
    a ← A + 1/8 Err
    D ← D + 1/4(Err| -D)
    RTO = A + 4D

  • 数据的交互:
    慢启动, 快重传, 拥赛避免策略 p235
  • 坚持计时器
    当对方的通告窗口为0是的测试窗口的策略(TCP/IP) 245

客户端

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/stat.h>
#include <sys/fcntl.h>
#include <time.h>
#include <unistd.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <pthread.h>void err_que(const char *msg)
{puts(msg);exit(0);
}void err_sys(const char *msg)
{printf("%s:%s\n", msg, strerror(errno));exit(errno);
}int main(int argc, char *argv[])
{int                                         sockfd;int                                         recv_len;int                                         fsize;int                                         index;int                                         cursize;int                                         file_fd;int                                         read_len;char                                        *file_name;char                                        filemsg[128];char                                        strbuff[128];struct sockaddr_in          serviceaddr;struct stat                         file_msg;struct timespec                 timestart, timeend;if(argc != 3)err_que("client Ipaddress filename");file_name = argv[2] + strlen(argv[2]) -1;while(*(file_name-1) != '/')file_name--;if(stat(file_name, &file_msg) != -1){if(!S_ISREG(file_msg.st_mode))err_que("file is exist in locale and it isn't a regeular file");while(1){write(STDOUT_FILENO, "file is exist are you replace it ?? (y|n) :\n", strlen("file is exist are you replace it ?? (y|n) :\n"));switch (getchar()) {case 'y':case 'Y':break;case 'n':case 'N':exit(0);break;default:while(getchar()!='\n');continue;}break;}}else if(errno != ENOENT)err_sys("stat file error");if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)err_sys("socket error");memset(&serviceaddr, 0, sizeof(serviceaddr));serviceaddr.sin_family = AF_INET;serviceaddr.sin_port    = htons(8068);if(inet_pton(AF_INET, argv[1], (void *)&serviceaddr.sin_addr.s_addr) == -1)err_sys("inet_pton error");// 链接服务器if(connect(sockfd, (struct sockaddr *)&serviceaddr, sizeof(serviceaddr)) == -1)err_sys("connect error");if(send(sockfd, argv[2], strlen(argv[2]), 0) == -1)err_sys("send error");memset(filemsg, 0, sizeof(filemsg));if(recv(sockfd, filemsg, sizeof(filemsg), 0) == -1)err_sys("recv error");if(!strncmp(filemsg, "file is not exist", strlen("file is not exist")))err_que("file is not exist in service");if(!strncmp(filemsg, "file read false", strlen("file read false")))err_que("file read false");sscanf(filemsg, "file size : %d", &fsize);if((file_fd = open(file_name, O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH)) == -1)err_sys("file open error");write(STDOUT_FILENO,"File is transport now :\n", strlen("File is transport now :\n"));write(STDOUT_FILENO,"==========================================================================================\n",strlen("==========================================================================================\n"));if(clock_gettime(CLOCK_REALTIME, &timestart) == -1)err_sys("clock_gettime error");cursize = 0;    // 当前已经读取的大小index   = 0;    // 当前的点数while(read_len=recv(sockfd, strbuff, sizeof(strbuff), 0)){int i;if(read_len == -1)err_sys("read_error");cursize += read_len;for(i =0; i < (int)((double)cursize/fsize * 90)-index; i++)write(STDOUT_FILENO, "#", 1);index = (int)((double)cursize/fsize * 90);if(write(file_fd, strbuff, read_len) == -1)err_sys("send error");}if(clock_gettime(CLOCK_REALTIME, &timeend) == -1)err_sys("clock_gettime error");printf("\nUsetime : %d:%d\n", timeend.tv_sec - timestart.tv_sec, timeend.tv_nsec-timestart.tv_nsec);close(sockfd);return 0;
}

服务器端

#include <sys/socket.h>
#include <netinet/in.h>
#include <signal.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/fcntl.h>
#include <sys/stat.h>
#include <sys/epoll.h>
#include <sys/resource.h>
#include <unistd.h>
#include <pthread.h>
#include <signal.h>
#include <string.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <time.h>#define LOGEFILE "./.saligia_ftp_log"       // 日志文件
#define LOCKFILE "./.saligia_ftp_lock"  // 文件互斥锁// 测试是否有相同的进程开启
void test_service(void);
// 开启守护进程
void daemon_set(int stdfd);
// 向客户端发送数据请求
void *serv_to_client(void *msg);
// 获取当地时间
void get_time(char *msg);
// 中止信号处理
void sigint_chose(int signo);void err_sys(const char *msg)
{char err_msg[128];memset(err_msg, 0, sizeof(err_msg));sprintf(err_msg, "%s:%s\t", msg, strerror(errno));get_time(err_msg);write(STDOUT_FILENO, err_msg, strlen(err_msg));exit(errno);
}
void err_que(const char *msg)
{char err_msg[128];memset(err_msg, 0, sizeof(err_msg));sprintf(err_msg, "%s\t", err_msg);get_time(err_msg);write(STDOUT_FILENO, err_msg, strlen(err_msg));exit(0);
}typedef struct{char file_name[128];int  client_sock;
}CLIMSG, *PCLIMSG;int main(int argc, char *argv)
{int                                     logfd;int                                     service_fd;int                                     epoll_fd;int                                     epoll_len;int                                     index;int                                     sockopton;pthread_t                           pthclient;int                                     clientaddrlen;int                                     clientsockfd;char                                    err_msg[128];char                                    log_msg[128];char                                    file_name[128];char                                    ip_addr[INET_ADDRSTRLEN];struct sockaddr_in      service_addr;struct sockaddr_in      client_addr;struct epoll_event      set_event;struct epoll_event      listen_events[10];struct timespec             nowtime;struct tm                           *showtime;struct stat                     filemsg;pthread_attr_t              pthread_msg;//创建日至记录文件if((logfd = open(LOGEFILE, O_RDWR|O_APPEND|O_CREAT, S_IRUSR|S_IWUSR)) == -1)err_sys("open error");daemon_set(logfd);// 创建服务器socketif((service_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1)err_sys("socket error");// 创建监听池来接受数据if((epoll_fd = epoll_create(10)) == -1)err_sys("epoll error");// 绑定套接字memset(&service_addr, 0, sizeof(service_addr));service_addr.sin_family         = AF_INET;service_addr.sin_port           = htons(8068);service_addr.sin_addr.s_addr    = INADDR_ANY;sockopton = 1;if(setsockopt(service_fd, SOL_SOCKET, SO_REUSEADDR, &sockopton, sizeof(sockopton)) == -1)err_sys("setsockopt error");if(bind(service_fd, (struct sockaddr*)&service_addr, sizeof(service_addr)) == -1)err_sys("bind error");if(listen(service_fd, 10) == -1)err_sys("listen error");// 将 service 套接字加入监听池memset(&set_event, 0, sizeof(set_event));set_event.events    = EPOLLIN|EPOLLOUT;set_event.data.fd   = service_fd;if(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, service_fd, &set_event) == -1)err_sys("epoll_ctl error");while(1){// 监听套接字事件if((epoll_len = epoll_wait(epoll_fd, listen_events, 10, 10000000)) == -1)err_sys("epoll_wait error");for(index=0; index<epoll_len; index++){//来自 LISTEN 套接字的事件if(listen_events[index].data.fd == service_fd){if(listen_events[index].events & EPOLLERR){memset(err_msg, 0, sizeof(err_msg));sprintf(err_msg,"listen_events error : %s\n", strerror(errno));if(write(STDOUT_FILENO, err_msg, strlen(err_msg)) == -1)err_sys("write error");}else if(listen_events[index].events & EPOLLIN){clientaddrlen=sizeof(client_addr);if((clientsockfd = accept(service_fd, (struct sockaddr *)&client_addr, &clientaddrlen)) == -1)err_sys("accept error");memset(log_msg, 0, sizeof(log_msg));sprintf(log_msg, "%-15s:%05d\t\t%-30s\t",inet_ntop(AF_INET, (void *)&client_addr.sin_addr.s_addr, ip_addr, INET_ADDRSTRLEN),ntohs(client_addr.sin_port), "client connect");get_time(log_msg);if(write(STDOUT_FILENO, log_msg, strlen(log_msg)) == -1)err_sys("write error");set_event.events = EPOLLIN | EPOLLERR;set_event.data.fd = clientsockfd;if(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, clientsockfd, &set_event) == -1)err_sys("epoll_ctl error");}}else // 普通用户的连接请求{int clientfd = listen_events[index].data.fd;if(listen_events[index].events & EPOLLERR){memset(log_msg, 0, sizeof(log_msg));sprintf(log_msg, "client link error\t");get_time(log_msg);if(write(STDOUT_FILENO, log_msg, strlen(log_msg)) == -1)err_sys("write error");if(epoll_ctl(epoll_fd, EPOLL_CTL_DEL,clientfd , &listen_events[index]) == -1)err_sys("epoll_ctl error");close(clientfd);}else if(listen_events[index].events & EPOLLIN){memset(file_name, 0, sizeof(file_name));if(recv(clientfd, file_name, sizeof(file_name), 0) == -1)err_sys("recv error");// 记录用户请求文件信息clientaddrlen = sizeof(client_addr);if(getpeername(clientfd, (struct sockaddr *)&client_addr, &clientaddrlen) == -1)err_sys("getpeername error");if(inet_ntop(AF_INET, &client_addr.sin_addr.s_addr, ip_addr, INET_ADDRSTRLEN) == NULL)err_sys("inet_ntop error");memset(log_msg, 0, sizeof(log_msg));sprintf(log_msg, "%-15s:%05d\t\t%-30s\t",ip_addr, ntohs(client_addr.sin_port),file_name);get_time(log_msg);if(write(STDOUT_FILENO, log_msg, strlen(log_msg)) == -1)err_sys("write error");if(stat(file_name, &filemsg) == -1){if(errno = ENOENT){send(clientfd, "file is not exist", strlen("file is not exist"), 0);if(epoll_ctl(epoll_fd, EPOLL_CTL_DEL,clientfd , &listen_events[index]) == -1)err_sys("epoll_ctl error");close(clientfd);}elseerr_sys("stat error");}else if(access(file_name, R_OK) == -1){if(errno == EACCES){send(clientfd, "file read false", strlen("file read false"), 0);if(epoll_ctl(epoll_fd, EPOLL_CTL_DEL,clientfd , &listen_events[index]) == -1)err_sys("epoll_ctl error");close(clientfd);}elseerr_sys("access error");}else{char SND_MSG[128];memset(SND_MSG, 0, sizeof(SND_MSG));sprintf(SND_MSG, "file size : %d", filemsg.st_size);if(send(clientfd, SND_MSG, strlen(SND_MSG), 0) == -1)err_sys("send error");PCLIMSG climsg = (PCLIMSG)malloc(sizeof(CLIMSG));memset(climsg, 0, sizeof(CLIMSG));strcpy(climsg->file_name, file_name);climsg->client_sock=clientfd;if(pthread_attr_init(&pthread_msg) == -1)err_sys("pthread_attr_init error");if(pthread_attr_setdetachstate(&pthread_msg, PTHREAD_CREATE_DETACHED) == -1)err_sys("pthread_attr_setdetached error");if(pthread_create(&pthclient, &pthread_msg, serv_to_client, climsg) != 0)err_sys("pthread_create error");if(epoll_ctl(epoll_fd, EPOLL_CTL_DEL,clientfd , &listen_events[index]) == -1)err_sys("epoll_ctl error");}}}}}return 0;
}
void test_service(void)
{int                     lockfd;struct flock    lockmsg;if((lockfd = open(LOCKFILE, O_RDWR)) == -1)err_sys("file open error");memset(&lockmsg, 0, sizeof(lockmsg));lockmsg.l_type      = F_WRLCK;lockmsg.l_whence    = SEEK_SET;lockmsg.l_start     = 0;lockmsg.l_len       = 0;if(fcntl(lockfd, F_SETLK, &lockmsg) == -1){if(errno == EAGAIN)exit(0);elseerr_sys("fcntl F_SETLK error");}}
void daemon_set(int stdfd)
{int                         pid;int                         index;char                        log_msg[128];struct rlimit   filerlimit;sigset_t                sigblock;// 屏蔽终端字sigemptyset(&sigblock);sigaddset(&sigblock, SIGHUP);if(sigprocmask(SIG_BLOCK, &sigblock, NULL) == -1)err_sys("sigprocmask error");// 关闭所有的以打开的文件描述符if(getrlimit(RLIMIT_NOFILE, &filerlimit) == -1)err_sys("getrlimit error");for(index = 0; index < filerlimit.rlim_cur; index++)if(index != stdfd)close(index);// 重定义标准输入输出流if(fcntl(stdfd, F_DUPFD, 0) == -1)err_sys("fcntl error");if(fcntl(stdfd, F_DUPFD, 1) == -1)err_sys("fcntl error");if(fcntl(stdfd, F_DUPFD, 2) == -1)err_sys("fcntl error");if((pid = fork()) == -1)err_sys("fork error");if(pid != 0)exit(0);setsid();if((pid = fork()) == -1)err_sys("fork error");if(pid != 0)exit(0);test_service();memset(log_msg, 0, sizeof(log_msg));sprintf(log_msg, "service is opening\t");get_time(log_msg);if(write(STDOUT_FILENO, log_msg, strlen(log_msg)) == -1)err_sys("write error");
}
void *serv_to_client(void *msg)
{char                                    msg_buf[128];char                                    sysmsg[128];int                                     req_fd;int                                     read_len;int                                     clientaddrlen;sigset_t                        sigmask;struct timespec             starttime, endtime;PCLIMSG climsg = (PCLIMSG) msg;sigemptyset(&sigmask);sigaddset(&sigmask, SIGPIPE);if(pthread_sigmask(SIG_BLOCK, &sigmask, NULL) != 0)err_sys("pthread_sigprocmask error");if((req_fd = open(climsg->file_name, O_RDONLY)) == -1)err_sys("open error");if(clock_gettime(CLOCK_REALTIME, &starttime) == -1)err_sys("clock_gettime error");while(read_len = read(req_fd, msg_buf, sizeof(msg_buf))){if(read_len == -1)err_sys("read error");if(send(climsg->client_sock, msg_buf, read_len, 0) == -1)break;}if(clock_gettime(CLOCK_REALTIME, &endtime) == -1)err_sys("clock_gettime error");memset(sysmsg, 0, sizeof(sysmsg));if(read_len == 0)sprintf(sysmsg, "%-40s\t file transport success :\t\t %d:%d\n",climsg->file_name, endtime.tv_sec-starttime.tv_sec, endtime.tv_nsec-starttime.tv_nsec);elsesprintf(sysmsg, "%-40s\t file transport false :\t\t %d:%d\n",climsg->file_name, endtime.tv_sec-starttime.tv_sec, endtime.tv_nsec-starttime.tv_nsec);write(STDOUT_FILENO, sysmsg, strlen(sysmsg));close(req_fd);close(climsg->client_sock);free(climsg);return NULL;
}void get_time(char *msg)
{struct timespec timenow;struct tm           *showtime;char                        *p;if(msg == NULL)err_que("time buff is null");p = msg + strlen(msg);if(clock_gettime(CLOCK_REALTIME, &timenow) == -1)err_sys("clock_gettime error");if((showtime = localtime(&timenow.tv_sec)) == NULL)err_que("localtime error");sprintf(p, "%02d-%02d  %02d:%02d:%02d\n", showtime->tm_mon+1, showtime->tm_mday,showtime->tm_hour, showtime->tm_min, showtime->tm_sec);
}

UNP-基本TCP编程-2(复用技术)相关推荐

  1. Linux(服务器编程):25---epoll复用技术实现统一处理信号事件源

    一.统一信号处理事件源概述 信号是一种异步事件:信号处理函数和程序的主循环是两条不同的执行路线.显然,信号处理函数需要尽可能快地执行完毕,以确保该信号不被屏蔽(为了避免一些竞态条件,信号在处理期间,系 ...

  2. Unix网络编程(六)高级I/O技术之复用技术 select

    转载:http://blog.csdn.net/michael_kong_nju/article/details/44887411 I/O复用技术 本文将讨论网络编程中的高级I/O复用技术,将从下面几 ...

  3. TCP/IP网络编程——IO复用

    引入复用技术,可以减少进程数,无论连接多少客户端,提供服务的进程只有一个. select函数可以实现IO复用,它可以将多个文件描述符集中到一起统一监视: 是否存在套接字接收数据?无需阻塞传输数据的套接 ...

  4. 计算机网络TCP/IP:物理层(信道,调制,香农极限,信道复用技术,宽带接入技术)

    物理层是什么? 物理层是TCP/IP协议的最底层,但并不意味着这一层是实体,不是指具体的传输媒体,物理层要尽可能的屏蔽掉不同传输媒体和通信手段的差异,为它的上层提供数据通讯服务 数据通信的基础知识 信 ...

  5. java io复用_学习Java编程-IO复用

    原标题:学习Java编程-IO复用 对于服务器的并发处理能力,我们需要的是:每一毫秒服务器都能及时处理这一毫秒内收到的数百个不同TCP连接上的报文,与此同时,可能服务器上还有数以十万计的最近几秒没有收 ...

  6. 软件的复用技术及开发方法

    软件的复用技术及开发方法 2.1软件的复用技术 软件复用是指在开发新的软件系统时,对已有的软件或软件模块重新使用,该软件可以是己经存在的软件,也可以是专门的可复用组件[8].软件可复用性的高低影响到生 ...

  7. android xml java混合编程_Java学习中注解与多线程,网络编程与XML技术

    本部分内容主要有集合框架及泛型,实用类,输入和输出处理,注解与多线程,网络编程与XML技术.初次学习这部分会感觉很难,主要是概念难于理解,最好是多看看例子,多练习.下面是个人的总结 拉勾IT课小编为大 ...

  8. Linux 网络编程——TCP编程

    概述 TCP(Transmission Control Protocol 传输控制协议)是一种面向连接的.可靠的.基于字节流的传输层通信协议. TCP 具有以下特点: 1)电话系统服务模式的抽象 2) ...

  9. 基于光纤通信复用技术的毕业设计

    文末下载完整资料 [摘 要] 在光纤通信中,复用技术被认为是扩展现存光纤网络工程容量的主要手段.复用技术主要包括时分复用TDM(Time Division Multiplexing)技术.空分复用SD ...

最新文章

  1. 课程实验代码及动手动脑测试
  2. SLAM精度测评——EVO进阶
  3. 将Centos的yum源更换为国内的阿里云源
  4. Leetcode刷题 225题:用队列实现栈(基于Java和c++两种语言)
  5. websocket趣说_转
  6. WebMagic功能——XPath、CSS选择器、正则表达式 || 抽取元素API、获取结果API || ​​​​​​​获取链接||​​​​​​​使用Pipeline保存结果
  7. 【Web安全】JSP内存马研究
  8. C语言解释器的实现--语法解析(五)
  9. 使用Spring Roo进行快速云开发–第1部分:Google App Engine(GAE)
  10. TCP多进程并发服务端 Linux socket编程入门(2)
  11. android studio 2.3 instant run,android studio 2.3 instant run not working
  12. iOS8开发-Swift编程
  13. 如何使用 indent 美化你的代码
  14. TCHAR、WCHAR、CHAR以及WideCharToMultiByte、MultiByteToWideChar
  15. 运动计步app开发的功能分析
  16. 在深圳,考PMP需要花费多少钱?
  17. 比较不错的MaciOS软件论坛
  18. 【渝粤教育】电大中专学前教育学_1作业 题库
  19. 谷歌浏览器下面的任务栏不见了
  20. java学习的电脑_请问学习java需要什么配置的笔记本电脑?

热门文章

  1. 【深度学习笔记(十)】之物体检测(R-CNN,Fast R-CNN, Faster R-CNN)
  2. matlab unifit,【matlab】matlab在概率统计中的应用(二)
  3. 【python】注意力机制代码
  4. 计算机组成原理实验:全加器实验
  5. java项目中获取真实ip地址
  6. python-gitlab
  7. 多场景项目实战 (总结有点多今天)
  8. 数据库的表、字段、字段的值的相关操作
  9. 关于cpu limit 和memory limit 的一些资料
  10. Linux配置ssh远程连接服务