网络LinuxLinux网络编程-TCP,UDP套接字编程及代码示范

Posted zhaocx111222333

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了网络LinuxLinux网络编程-TCP,UDP套接字编程及代码示范相关的知识,希望对你有一定的参考价值。


本文我们分为TCP和UDP协议网络程序的编写:
他们的区别如下:

项目特点
UDP用户数据报协议,无需连接,不可靠,面向数据报,其实时性>可靠性(典型的就是视频传输)
TCP传输控制协议,面向连接,可靠,面向字节流,其可靠性>实时性(文件传输)

UDP类

  1 #include <cstdio>                                                                                                                                                                     
  2 #include <iostream>
  3 #include <string>
  4 #include <unistd.h>
  5 #include <arpa/inet.h>
  6 #include <netinet/in.h>
  7 #include <sys/socket.h>
  8 //dup网络协议类
  9 //需要实现5个接口,
 10 //1.创建套接字
 11 //2.绑定地址信息(一般是服务器端需要)
 12 //3.发送数据
 13 //4.接受数据
 14 class UDPSocket{
 15 //套接字的成员变量就是套接字操作句柄
 16   private:
 17     int _sockfd;
 18 
 19   public:
 20 
 21     UDPSocket()
 22       :_sockfd(-1){}
 23     //创建套接字
 24     //socket(地址域类型,套接字类型,本次通信协议)
 25     bool Socket(){
 26     _sockfd=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
 27       if(_sockfd<0){
 28         perror("socket error");
 29         return false;
 30       }
 31       return true;
 32     }
 33 
 34 
 35   //绑定地址信息(套接字操作句柄,addr结构体地址信息指针,地址信息长度)
 36   //不同的通讯协议地址信息大小不同
 37   //统一的接口是sockaddr(为了接口规范)16字节
 38   //ipv4是sockaddr_in 16字节
 39   //封装的接口需要ip地址和port值
 40     bool Bind(const std::string &ip,uint16_t port){
 41       struct sockaddr_in addr;
 42       addr.sin_family=AF_INET;
 43       addr.sin_port=htons(port);
 44       addr.sin_addr.s_addr=inet_addr(ip.c_str());
 45       socklen_t len=sizeof(struct sockaddr_in);
 46       int ret;
 47       //第二参数要穿地址!!
 48       ret=bind(_sockfd,(struct sockaddr*)&addr,len);
 49       if(ret<0){
 50         perror("bind error");
 51         return false;
 52       }
 53       return true;
 54     }
 55     
 56 
 57     //发送数据接口
 58     //(套接字操作句柄,发送空间首地址,数据长度,0阻塞,对端地址信息,对端地址结构长度)
 59    //封装的接口要数据的地址信息,对端ip和port
 60    //注意ip是const,可以直接以"192.0.0.0"格式发送,否则只能是string类型
 61    //因为"192.0.0.0"是常量字符串
 62     bool Send(std::string& data,const std::string &ip,u_int16_t port){
 63       struct sockaddr_in addr;
 64       addr.sin_family=AF_INET;                                                                                                                                                         
 65       addr.sin_port=htons(port);
 66       addr.sin_addr.s_addr=inet_addr(ip.c_str());
 67       socklen_t len=sizeof(struct sockaddr_in);
 68       int ret=sendto(_sockfd,data.c_str(),data.size(),0,(sockaddr*)&addr,len);
 69       if(ret<0){
 70         perror("sendto error");
 71         return false;
 72       }
 73       return true;
 74     }
 75 
 76   //接受数据(操作句柄,接受空间地址,接收数据长度,0阻塞,(输出参数)发送源端地址信息,(输入输出型参数)指定接收的地质结构大小,返回实际的大小)   
 77   ///封装的接口是接受地址,接收发送方ip和port的地址(一般情况可以不接受,指定为NULL表示不需要直到发送方的信息)
 78     bool Recv(std::string * buf,std::string* ip=NULL,int * port=NULL){
 79       struct sockaddr_in addr;
 80       socklen_t len=sizeof(struct sockaddr_in);
 81       char tmp[1024]={0};
 82       int ret=recvfrom(_sockfd,tmp,1024,0,(sockaddr*)&addr,&len);
 83       if(ret<0){
 84         perror("sendto error");
 85             return false;                    
 86       }
 87       //ret为世界接收到的数据长度
 88       buf->assign(tmp,ret);
 89 
 90       if(ip!=NULL){
 91         *ip=inet_ntoa(addr.sin_addr);
 92       }
 93       if(port!=NULL){
 94         *port=ntohs(addr.sin_port);
 95       }
 96       return true;
 97     }
 98 
 99     //关闭套接字
100     bool Close(){
101       if(_sockfd!=-1){
102         close(_sockfd);
103       }
104       return true;
105     }
106                                                                                                                                                                                        
107 };

UDP服务端单执行流

  1 #include"classudp.hpp"
  2 
  3 #define CHECK_RET(q) if((q)==false){return -1;}
  4 //服务端需要做的步骤:
  5 //1.创建套接字
  6 //2.绑定地址信息
  7 //3.接收数据,(如果需要反馈给客户端则需要记录地址信息)
  8 //4.发送数据
  9 int main(){
 10   UDPSocket ssock;
 11   CHECK_RET(ssock.Socket());
 12   CHECK_RET(ssock.Bind("192.168.107.128",9000));
 13   while(1){
 14     std::string buf;
 15     int cliport;
 16     std::string clip;
 17     CHECK_RET(ssock.Recv(&buf,&clip,&cliport));
 18     std::cout<<"client say: "<<buf<<std::endl;
 19     buf.clear();//清空缓冲区                                                                                                                                                           
 20     std::cout<<"server say: ";
 21     std::cin>>buf;
 22     CHECK_RET(ssock.Send(buf,clip,cliport));
 23   }
 24   ssock.Close();
 25   return 0;
 26 }

UDP客户端

  1 #include "classudp.hpp"
  2 
  3 #define CHECK_RET(q) if((q)==false){return -1;}
  4 //客户端的任务流程
  5 //1.创建套接字
  6 //2.绑定地址结构
  7 //3.发送数据
  8 //4.接受数据
  9 //5.关闭套接字
 10 int main(){
 11 //1.
 12   UDPSocket sock;
 13   CHECK_RET(sock.Socket());
 14 //2.
 15 //3.
 16   while(1){
 17     std::cout<<"client saY:";
 18     std::string buf;
 19     std::cin>>buf;
 20     CHECK_RET(sock.Send(buf,"192.168.107.128",9000));
 21 
 22 
 23 //4.
 24     buf.clear();//不用的缓冲区清空
 25     CHECK_RET(sock.Recv(&buf));//用发送缓冲区接收,不接收源端信息就不写
 26     std::cout<<"server say: "<<buf<<std::endl;
 27   }
 28 //5.
 29   sock.Close();
 30   return 0;                                                                                                                                                                            
 31 }

TCP类

    1 #include <cstdio>
    2 #include <iostream>
    3 #include <string>                                                                                                                                                                                            
    4 #include <unistd.h>
    5 #include <arpa/inet.h>
    6 #include <netinet/in.h>
    7 #include <sys/socket.h>
    8 
    9 #define LISTEN_MAX 5
   10 #define CHECK_RET(q) if((q)==false){return -1;}
   11 //tcp的流程大致如下“
   12 //客户端:创建套接字,不推荐绑定地址信息,向服务器发送链接请求,收发数据,关闭套接字
   13 //服务端:创建套接字,绑定地址信息,开始监听,获取新建连接,收发数据,关闭套接字
   14 class TCPSocket{
   15   private:
   16     int _sockfd;
   17   public:
   18     TCPSocket():_sockfd(-1){}
   19     //创建套接字
   20     //socket(地址域类型,套接字类型,通信协议)
   21     //封装的接口需要获取操作句柄
   22     bool Socket(){
   23       _sockfd = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
   24       if(_sockfd<0){
   25         perror("socket error");
   26         return false;
   27       }
   28       return true;
   29     }
   30 
   31     //绑定地址信息
   32     //接口(句柄,规范接口struct结构体,结构体大小)、
   33     //封装的接口(ip地址,port信息)
   34     bool Bind(const std::string &ip,const uint16_t port){
   35       sockaddr_in addr;
   36       addr.sin_family = AF_INET;//16位地址类型
   37       addr.sin_port = htons(port);
   38 
   39       //这两种都能拿到ip内容(str的首地址)
   40       addr.sin_addr.s_addr = inet_addr(&ip[0]);
   41       //addr.sin_addr.s_addr = inet_addr(ip.c_str());
   42 
   43       socklen_t len = sizeof(sockaddr_in);
   44       int ret=bind(_sockfd,(struct sockaddr*)&addr,len);
   45 
   46       if (ret < 0) {
   47         perror("bind error");
   48         return false;
   49       }
   50       return true;
   51   
   52     }
   53     
   54 
   55     //监听接口(操作句柄,最大连接数)
   56     //封装接口(最大连接数)
W> 57     bool Listen(int big =LISTEN_MAX){
   58       int ret=listen(_sockfd,LISTEN_MAX);
   59       if(ret<0){
   60         return false;
   61       }
   62       return true;
   63     }
   64 
   65 
   66 
   67     //申请链接(操作句柄,服务端的地址,地址长度)
   68     //封装的接口(服务器ip,服务器port)
   69     bool Connect(const std::string &ip,uint16_t port){
   70       sockaddr_in addr;
   71       addr.sin_family = AF_INET;
   72       addr.sin_port = htons(port);
   73       addr.sin_addr.s_addr = inet_addr(&ip[0]);
   74       socklen_t len = sizeof(sockaddr_in);
   75       int ret = connect(_sockfd, (sockaddr*)&addr, len);
   76       if (ret < 0) {
   77         perror("connect error");
   78         return false;
   79     }
   80       return true;
   81     }
   82                                                                                                                                                                                                              
   83     //封装的接口:
   84     //注意三个都是输出型参数(因为是处理请求的接口,所以不需要输入什么信息,只需要获得)
   85     //服务器同意链接接口(新的套接字地址,客户端的地址结构指针,地址结构大小指针)
   86     //注意这个的前提是客户端发送请求了,所以后两个数输出结构,用来获取请求的客户端的地址信息,当然可以不获取
   87     
   88     //原始的的接口(监听套接字,获取客户端的ip,客户端的port地址)
   89     //返回值是一个新的套接字,专门用来服务客户端,所以监听套接字相当于门迎~
   90     //将返回值放到封装的接口参数1,原始接口2是输出参数,分开封装到封装接口的23
   91     bool Accept(TCPSocket *sock,std::string *ip=NULL,uint16_t *port=NULL){
   92       //建立一个结构体用来存客户端的地址信息
   93       sockaddr_in addr;
   94       socklen_t len = sizeof(sockaddr_in);
   95 
   96       //注意这个len是输出型参数,所以是取地址!!!!
   97       int newfd=accept(_sockfd,(sockaddr*)&addr,&len);
   98       if (newfd < 0) {
   99         perror("accept error");
  100         return false;
  101     }
  102 
  103       //将输出型参数1填复制的句柄
  104       sock->_sockfd = newfd;
  105       if (ip != NULL) {
  106            *ip = inet_ntoa(addr.sin_addr);             
  107       }                                                  
  108       if (port != NULL) {
  109            *port = ntohs(addr.sin_port);             
  110       }
  111          return true;
  112     
  113   }
  114 
  115   
  116     //接收数据(操作句柄,接收缓冲区,接收数据长度,0阻塞)
  117     //封装的接口(接收缓冲区)
  118     //注意返回值小于0错误
  119     //等于0连接断开
  120     //大于0,实际大小
  121     bool Recv(std::string *buf){
  122       char tmp[1024]={0};
  123       int ret=recv(_sockfd,tmp,1024,0);
  124       if (ret < 0) {                                                                                                                                                                                         
  125         perror("recv error");
  126         return false;
  127       }
  128       else if (ret == 0) {
  129 
  130         printf("peer shutdown");
  131         return false;
  132       }
  133       //把缓冲区的内容放入真正的缓冲区
  134       //因为原始接口需要指定一次接受的数据大小
  135       //而直接用缓冲区接收不能确定大小
  136       buf->assign(tmp, ret);
  137       return true;
  138     }
  139 
  140     //发送数据(描述符,数据,长度,标志位0阻塞)
  141     //封装的接口(要发送数据)
  142     //返回实际的长度
  143     //这里需要考虑一次发送不完全部数据该怎么办
  144     bool Send(const std::string &data){
  145     int total;
W>146     while(total < data.size())以上是关于网络LinuxLinux网络编程-TCP,UDP套接字编程及代码示范的主要内容,如果未能解决你的问题,请参考以下文章

TCP/IP和UDP之间的区别(转载)

Qt编写图片及视频TCP/UDP网络传输

王道考研 计算机网络19 传输层 传输层的寻址与端口 TCP UDP

TCP和UDP比較

网络协议篇UDP协议

再谈Http和Https及TCP/UDP/IP协议分析,面试官都惊讶的网络见解