TCP、UDP的传输及多线程多进程传输

网络基础的讲解:

https://blog.csdn.net/Z_JUAN1/article/details/81281606

 

socket常见API

     从应用层到传输层有一个接口:socket API 接口

     因此不管是服务器还是客户端在通信时都需要创建socket

一、这是UDP socket的流程

服务器整体思想:

    创建socket,绑定地址端口,就可以进行数据传输

客户端整体思想:

   创建socket,直接进行数据传输

二、这是TCP socket的流程

服务器端的整体思想:

1.有两类socket,一类用于监听,一类用于传输

listen和accpet做得事情

     先创建socket,然后绑定这个地址端口,在对这个地址进行监听,此时客户端若发送一个连接请求,服务器接收成功后从连接队列里面取出一个已经连接好的socket,返回这个socket的文件描述符,此时这个socket专门用于数据通信。

   

三、接口函数:

     创建socket文件描述符

     绑定地址端口

监听函数

接收请求

连接成功,他会从连接成功的队列中取出一个已经连接成功的socket,返回socket的文件描述符,专门用于数据通信

四、地址转化函数

inet_addr();

          将一个点分十进制的字符串转化为一个网络字节序

char * inet_ntoa();(全局静态变量,要慎用,内存会覆盖) (再多线程中可以使用inet_ntop)

        将一个主机IP转为字符串

htonl();

         是将一个32位长整数的主机字节序转为网络字节序,(包含了验证大小端)

htons();

        是将一个16位短整数的主机字节序转为网络字节序,

ntohl();

        将一个网络字节序转为32为长整数的主机字节序

ntohs();

        将一个网络字节序转为32为长整数的主机字节序

五、代码

       1) udp   

                   1.服务器:

                                

  1 /*
  2  * udp服务端程序:简单聊天服务器端
  3  *    1.创建socket      socket()
  4  *    2.为socket绑定地址信息  bind()
  5  *    3.接收发送数据   sendto()/recfrom()
  6  *    4.关闭socket  close()
  7  */
  9 #include<stdlib.h>
 10 #include<sys/socket.h>
 11 #include<netinet/in.h>
 12 #include<arpa/inet.h>
 13 #include<unistd.h>
 14 #include<errno.h>
 15 #include<string.h>
 16 int main()
 17 {
 18         int sockfd=-1;
 19         socklen_t len;
 20         //创建sock接口 (协议组,类型,方式)
 21         sockfd=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
 22         if(sockfd<0){
 23                 perror("socket");
 24                 return -1;
 25         }
 26         //结构体 IPv4
 27         struct sockaddr_in local;
 28         local.sin_family=AF_INET;//哪个协议组
 29         local.sin_port=htons(9000);//端口号
 30         local.sin_addr.s_addr=inet_addr("192.168.239.128");//地址
 31         int ret;
 32         len=sizeof(struct sockaddr_in);//结构体大小
 33         //绑定端口号(描述符,地址,大小)
 34         ret=bind(sockfd,(struct sockaddr*)&local,len);
 35         if(ret<0){
 36                 perror("bind");
 37                 return -1;
 38         }
 39         while(1){
 40                 char buff[1024]={0};
 41                 ssize_t s;
 42                 //接收数据(描述符,放到哪,内存大小,阻塞,从哪来,数据大小)
 43                 s= recvfrom(sockfd,buff,1023,0,(struct sockaddr*)&local,&len);
 44                 printf("%s\n",buff);
 45 
 46                 char tmp[1024]={0};
 47                 printf("you say");
 48                 scanf("%s",tmp);
 49                 //发送数据(描述符,从哪取,内存大小,阻塞,到哪去,数据大小)  
 50                 sendto(sockfd,tmp,strlen(tmp),0,(struct sockaddr*)&local,len);
 51         }
 52         close(sockfd);
 53         return 0;
 54 }

              2.客户端:

        

 16 int main()
 17 {
 18         int sockfd;
 19         socklen_t len;
 20         //创建sock接口 (协议组,类型,方式)
 21         sockfd=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
 22         if(sockfd<0){
 23                 perror("socket");
 24                 return -1;
 25         }
 26         //结构体 IPv4
 27         struct sockaddr_in server;
 21         sockfd=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
 22         if(sockfd<0){
 23                 perror("socket");
 24                 return -1;
 25         }
 26         //结构体 IPv4
 27         struct sockaddr_in server;
 28         server.sin_family=AF_INET;//哪个协议组
 29         server.sin_port=htons(9000);//端口号
 30         server.sin_addr.s_addr=inet_addr("192.168.239.128");//地址
 31         int ret;
 32         len=sizeof(struct sockaddr_in);//结构体大小
 33         //收发数据
 34         while(1){
 35                 char buff[1024]={0};
 36                 printf("you say:");
 37                 scanf("%s",buff);
 38                 len=sizeof(struct sockaddr_in);
 39                 //发送数据(,发的数据在哪,发到哪,)
 40                 sendto(sockfd,buff,strlen(buff),0,(struct sockaddr*)&server,len);
 41                 //接收数据(描述符,放到哪,内存大小,阻塞,从哪来,数据大小)
 42                 char tmp[1024]={0};
 43                 recvfrom(sockfd,tmp,1023,0,(struct sockaddr*)&server,&len);
 44                 printf("%s\n",tmp);
 45         }
 46         close(sockfd);
 47         return 0;
 48 }

运行结果:

    

 tcp:

      服务器

 10 /*
 11  * TCP---简单的网络聊天程序
 12  * 1.创建socket
 13  * 2.为socket绑定地址端口
 14  * 3.开始监听socket--告诉操作系统,开始接受连接请求,并且处理
 15  * 4.接收连接请求后--获取新连接的socket(sip sport dip dport proto(什么协议))
 16  * 5.收发数据--recv\send
 17  * 6.关闭socket
 18  */
 19 int main(int argc,char *argv[]){
 20     if(argc!=3){
 21     printf("use: ./tcp_server ip port\n");
 22     return -1;
 23     }
 24     //1.创建socket,专门用于监听
 25     int listen_fd;
 26     listen_fd=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
 27     if(listen_fd<0){
 28     perror("socket");
 29     return -1;
 30     }
 31     //2.绑定地址端口
 32     struct sockaddr_in listen_addr;
 33     listen_addr.sin_family=AF_INET;
 34     listen_addr.sin_port=htons(atoi(argv[2]));//(将字符串转为int整数)
 35     listen_addr.sin_addr.s_addr=inet_addr(argv[1]);
 36     socklen_t len;
 37 
 38     len=sizeof(struct sockaddr_in);
 39 
 40     int ret;
 41     bind(listen_fd,(struct sockaddr_in*)&listen_addr,len);
 42     if(ret<0){
 43     perror("bind");
 44     return -1;
 45     }
 46 
 47     //监听
 48     if(listen(listen_fd,5)<0){
 49     perror("listen");
 50     return -1;
 51     }
 52 
 53     while(1){
 54         struct sockaddr_in sock;//用于通信
 55         len=sizeof(struct sockaddr_in);
 56         int newfd;
 57         newfd= accept(listen_fd,(struct sockaddr_in *)&sock,&len);
 58         if(newfd<0){
 59         perror("accpet");
 60         continue;
 61         }
 62         while(1){
 63 
 64         char buff[1024]={0};
 65         ret=recv(newfd,buff,1023,0);
 66         if(ret==0){
 67         printf("peer shutdown!!!\n");
 68         break;
 60         continue;
 61         }
 50     return -1;
 51     }
 52 
 53     while(1){
 54         struct sockaddr_in sock;//用于通信
 55         len=sizeof(struct sockaddr_in);
 56         int newfd;
 57         newfd= accept(listen_fd,(struct sockaddr_in *)&sock,&len);
 58         if(newfd<0){
 59         perror("accpet");
 60         continue;
 61         }
 62         while(1){
 63 
 64         char buff[1024]={0};
 65         ret=recv(newfd,buff,1023,0);
 66         if(ret==0){
 67         printf("peer shutdown!!!\n");
 68         break;
 69         }
 70         else if(ret<0){
 71         if(errno==EINTR || errno==EAGAIN){
 72             continue;
 73             }
 74             break;
 75         }
 76 
 77         printf("client say:%s\n",buff);
 78 
 79     //  char tmp[1024];
 80     //  printf("input:");
 81     //  fflush(stdout);
 82     //  scanf("%s",tmp);
 83     //  send(newfd,tmp,strlen(tmp),0);
 84     }
 85     close(newfd);
 86     }
 87     close(listen_fd);
 88     return 0;
 89 }

客户端

 11 /*
 12  * TCP---简单的网络聊天程序--客户端
 13  * 1.创建socket    socket()
 14  * 2.为socket绑定地址--客户端不推荐手动绑定
 15  * 3.向服务器发起连接请求  connect()
 16  * 4.收发数据--recv\send
 17  * 5.关闭socket
 18  */
 19 void sigcb(int signo){
 20     printf("recv a signal:SIGPIPE\n");
 21 }
 22 int main(int argc,char *argv[]){
 23     if(argc!=3){
 24     printf("use: ./tcp_server ip port\n");
 25     return -1;
 26     }
 27  signal(SIGPIPE,sigcb);
 28     //1.创建socket
 29     int sockfd;
 30     sockfd=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
 31     if(sockfd<0){
 32     perror("socket");
 33     return -1;
 34     }
 35 
 36     struct sockaddr_in serv_addr;
 37     serv_addr.sin_family=AF_INET;
 38     serv_addr.sin_port=htons(atoi(argv[2]));//(将字符串转为int整数)
 39     serv_addr.sin_addr.s_addr=inet_addr(argv[1]);
 40     socklen_t len;
 41     len=sizeof(struct sockaddr_in);
 42 
 43      //向服务器发起连接
 44     int ret=connect(sockfd,(struct sockaddr_in*)&serv_addr,len);
 45     if(ret<0){
 46     perror("connect");
 47     return -1;
 48     }
 49     while(1){
 50         char buff[1024]={0};
 51         //printf("input:");
 52     //  fflush(stdout);
 53         sprintf(buff,"%s","i am client!!!");
 54     //  scanf("%s",buff);
 55         send(sockfd,buff,strlen(buff),0);
 56         sleep(1);
 57         //char tmp[1024];
 58     //  recv(sockfd,tmp,1024,0);
 59     //  ret=recv(sockfd,tmp,1024,0);
 60     //  printf("serv say:%s\n",tmp);
 61 
 62     }
 63     close(sockfd);
 64     return 0;
 65 }

在这里我们看到有一个信号:SIGPIPE.

   这是在发送数据的时候,系统检测到对端关闭,就会发送一个SIGPIPE信号,使进程退出。若我们不想让进程退出,那么我们可以自定义这个信号。

对于接收信号,有三种返回值:

    (1)>0  :接收数据成功

      (2)  =0  :检测到对端关闭

      (3)  <0  :出错,但有两个可原谅的错误  1.EINTR:被信号打断  2.EAGAIN:还在缓冲区里面

 

上面的通信都一对一的,那么对于有多个客户端用该如何处理:

    (1)多进程:           

    (2)多线程:

     代码:

 21 void *handler(void *arg)
 22 {
 23     int socked=(int)arg;
 24     while(1){
 25         char buff[1024]={0};
 26         int ret=recv(socked,buff,1023,0);
 27         printf("pthread:%lu,say:%s\n",pthread_self(),buff);
 28     }
 29     close(socked);
 30     return NULL;
 31 }
 32 int create_worker(int newfd){
 33     pthread_t tid;
 34     pthread_create(&tid,NULL,handler,(void *)newfd);
 35     pthread_detach(tid);
 36 }
 

 71     while(1){
 72         struct sockaddr_in sock;//用于通信
 73         len=sizeof(struct sockaddr_in);
 74         int newfd;
 75         newfd= accept(listen_fd,(struct sockaddr_in *)&sock,&len);
 76         if(newfd<0){
 77         perror("accpet");
 78         continue;
 79         }
 80     printf("new_fd=%d\n",newfd);
 81     create_worker(newfd);
 82     }
 83     return 0;
 84 }
-- INS

在这里我们看到线程我们采用detach的方式进行等待,因为我们不关心线程的返回值,之间让其退出

对于两种处理方法也是各有利弊:

       对于多进程来说:安全性比较高,传输比多线程慢

      对于多线程来说:占用资源少,传输数据快,但有可能会丢失数据

对于这两者来说,若进程或者线程太多,会导致cpu调度频繁,传输数据慢

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值