改进后的tcp协议代码,多线程tcp协议代码,三次握手,四次挥手,tcp沾包,Tcp的特点

虚拟机要处于桥接模式下
在liunx上我们用ifconfig来查看IP号在Windows上用ipconfig上查看;
在这里插入图片描述
之前的代码一次只能处理一个客户端
套接字文件描述符也是文件描述符是0,1,2…不可能小于0;
清空saddr;

一,服务器端的代码

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<assert.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>

int main()
{
   int sockfd=socket(AF_INET,SOCK_STREAM,0);创建套接字,它能通过网络进行数据的收发,第一个为用啥协议,创建套接字的类型tcp协议,第三个协议版本基本为0
                         ipv4    使用tcp    
   assert(sockfd!=-1);sockfd文件描述符
   struct sockaddr_in saddr,caddr;//saddr代表服务器端的地址,caddr代表客服端的地址
   memset(&saddr,0,sizeof(saddr));
   
   saddr.sin_family=AF_INET;地址家族
   
   saddr.sin_port=htons(6000);6000这个端口转化为网络字节序列
   
   saddr.sin_addr.s_addr=inet_addr("127.0.0.1");将字符串(ip地址)转化为无符号整形
                                   ifconfig命令找到的
   int res=bind(sockfd,(struct sockaddr*)&caddr,sizeof(saddr));将ip,地址与套接字绑定
   assert(res!=-1);
   
  res=listen(sockfd,5);5为监听队列大小
  
  assert(res!=-1);
  while(1)
  {
      int len=sizeof(caddr);
      int c=accept(sockfd,(struct sockaddr*)&saddr,&len);c是连接套接字 
      if(c<0)
      {
         continue;
      }
      printf("accept c=%d,caddr.ip=%s,caddr.port=%d\n",inet_ntoa(caddr.sin_addr),ntohs(caddr.sin_port));
      把ip转化为字符串打印  网络转为主机端口
      while(1)
      {如果客户端建立连接之后没有发送数据选择结束,那么服务器端也要结束
      char buff[128]={0};
      int num=recv(c,buff,127,0);收到的字节数
      if(num==0)说明客户端已经关闭了
      {
        break;
      }
      printf("buff=%s,num=%d\n",buff,num);
      send(c,"ok",2,0);
      }
      close(c);
  }
   close(sockfd);
   exit(0);
   
}

5是监听套接字的大小;
accept里的参数给出记录客户端IP和端口的那块空间;
把一个结构体转换成一个字符串;
网络转主机;
saddr记录套接字的地址;
在同一个网络里别人作为客户端发起链接(但是必须在同一网里)

看书liunx高性能服务

在这里插入图片描述

tcpdump抓包 查看三次握手

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
不会归0的方式
在这里插入图片描述
四次挥手
在这里插入图片描述
更改代码IP127.0.0.1

二,客户端的代码

#include<stdio,h>
#include<stdlib.h>
#include<string.h>
#include<assert.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>

int main()
{
   int sockfd=socket(AF_INET,SOCK_STREAM,0);
   assert(sockfd!=-1);
   struct sockaddr_in saddr;填写的是服务器的地址 端口
   memset(&saddr,0,sizeof(saddr));
   saddr.sin_family=AF_INET;
   saddr.sin_port=htons(6000);
   saddr.sin_addr.s_addr=inet_addr("127.0.0.1");
   int res=connect(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));
   assert(res!=-1);
   while(1)
   {
   printf("input\n");
   char buff[128]={0};
   fgets(buff,128,stdin);
   if(strncmp(buff,"end",3)==0)
   {
      break;
   }
   send(sockfd,buff,strlen(buff),0);
   memset(buff,0,127);
   recv(sockfd,buff,127,0);
   printf("buff=%s\n",buff);
  
}
 close(sockfd);
 exit(0);
 }

上述的客户端和服务端代码存在如下弊端
在这里插入图片描述
第二个客户端的连接还没有建立此时仍然是第一个客户端的连接
recv返回值是0退出while循环

三,多线程TCP协议代码

每次接受一个链接就创建一个线程,用来serv接收数据,如果一个连接阻塞在了recv这里;主线程不会阻塞;会继续创建新的线程

服务端代码

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<assert.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<pthread.h>

void*recv_thread(void*arg)
{
 int c=(int)arg;
 while(1)
 {
 char buff[128]={0};
 int n=recv(c,buff,127,0);
 if(n<=0)
 {
 break;
 }
 printf("recv(%d)=%s\n",c,buff);
 send(c,"ok",2,0);
 }
 printf("client close\n");
}

int main()
{
 int sockfd=socket(AF_INET,SOCK_STREAM,0);//创建套接字,他能通过网络进行数据的收发;           ipv4  使用tcp
 assert(sockfd!=-1);//sockfd文件描述符;
 struct sockaddr_in saddr,caddr;//saddr代表服务器端地址,caddr代表客户端地址;
 memset(&saddr,0,sizeof(saddr));
 saddr.sin_family=AF_INET;//地址家族
 saddr.sin_port=htons(6000);//将6000这个端口转化为网络字节序列
 saddr.sin_addr.s_addr=inet_addr("127.0.0.1");//将字符串(IP地址)转化为无符号整形 通过ifconfig命令查找IP号;
 int res=bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));//将ip地址与套接字绑定
 assert(res!=-1);
 res=listen(sockfd,5);//5为监听队列的大小
 assert(res!=-1);
 while(1)
  {
  int len=sizeof(caddr);
  int c=accept(sockfd,(struct sockaddr*)&saddr,&len);//c是连接套接字;
  if(c<0)
  {
   continue;
  }
  printf("accept c=%d",c);
  pthread_t id;
  pthread_create(&id,NULL,recv_thread,(void*)c);
 }
 exit(0);
}

客户端代码

和上述客户端代码相同
在这里插入图片描述
运行结果:
在这里插入图片描述

四,三次握手

三次握手发生在connect()之后
在这里插入图片描述

五,四次挥手

在这里插入图片描述

六,tcp沾包

在这里插入图片描述

解决沾包

双方收到数据后发给对方数据,另一方就在等待,不会发数据就不会粘包
在这里插入图片描述

每次只接收一个字节的内容(将服务器端代码修改)

在这里插入图片描述
输出结果
在这里插入图片描述

七,tcp的特点

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值