套接字编程

客户端:

  1. 创建套接字是进程与网卡建立联系
  2. 为套接字绑定地址信息(通常客户端并不推荐用户手动绑定地址信息)
  3. 发送数据(如果socket还没有绑定地址信息,这时候会选择一个合适的地址端口进行绑定)
  4. 接收数据
  5. 关闭套接字

服务端:

  1. 创建套接字是进程与网卡建立联系
  2. 为套接字绑定地址信息(ip  port)
  3. 接受数据
  4. 发送数据
  5. 关闭套接字

为了保证接收数据的合理性,操作系统会为不同的端口进程之间创建各自的套接字缓冲区

UDP(接口的封装) 

  1 #include<iostream>
  2 #include<string>
  3 #include<stdio.h>
  4 #include<unistd.h>
  5 #include<stdlib.h>
  6 #include<errno.h>
  7 #include<sys/socket.h>
  8 #include<netinet/in.h>
  9 #include<arpa/inet.h>
 10 
 11 class UdpSocket{
 12     public:
 13         UdpSocket():_sock(-1){}
 14         ~UdpSocket(){}
 15         bool Socket(){
 16             //int socket(int domain,int type,int protocol);
 17             //domain:地址域
 18             //      AF_INET : ipv网络地址协议
 19             //type:套接字类型
 20             //      SOCK_STREAM:流式套接字,默认协议 tcp 不支持udp
 21             //      SOCK_DGRAM:数据报套接字,默认协议udp,不支持tcp
 22             //protocol:协议类型
 23             //      0;使用默认协议
 24             //      6/IPPROTO_TCP    tcp协议
 25             //      17/IPPPROTO_UDP  udp协议
 26             //返回值:套接字句柄---文件描述符      失败 -1
 27             _sock=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
 28             if(_sock<0){
 29                 perror("socket error");
 30                 return false;
 31             }
 32             return true;
 33         }
 34         //bool bind(int sockfd,const struct sockaddr* addr,socklen_t addlen);
 35         //sockfd:创建套接字返回的描述符
 36         //addr:地址信息
 37         //addlen:地址信息长度
 38         //返回值:0 失败返回 -1
 39         bool Bind(std::string& ip,uint16_t port){
 40             struct sockaddr_in addr;
 41             addr.sin_family=AF_INET;
 42             //uint16_t htons(uint16_t hostshort);
 43             addr.sin_port=htons(port);
 44             //in_addr_t inet_addr(const char* cp);
 45             addr.sin_addr.s_addr=inet_addr(ip.c_str());
 46             socklen_t len=sizeof(struct sockaddr_in);
 47             int ret=bind(_sock,(struct sockaddr*)&addr,len);
 48             if(ret<0){
 49                 perror("bind error");
 50                 return false;
 51             }
 52             return true;
 53         }
 54         //ssize_t recvfrom(int sockfd,void* buf,size_t len,int flags,struct sockaddr* saddr
 55         // ,socklen_t* addrlen);
 56         //sockfd:套接字句柄
 57         //buf:用buf存储接收数据
 58         //len:想要接收的数据长度
 59         //flags:0--默认阻塞接受
 60         //saddr:发送端地址信息
 61         //addrlen:地址信息长度(输入输出型参数)不但要指定想接受多长还要保存实际接受了多长
 62         //返回值:实际接受长度   失败:-1
 63         bool RecvFrom(std::string& buf,struct sockaddr_in* saddr){
 64             char tmp[1024]={0};
 65             socklen_t len=sizeof(struct sockaddr_in);
 66             int ret=recvfrom(_sock,tmp,1500,0,(struct sockaddr*)saddr,&len);
 67             if(ret<0){
 68                 perror("recvfrom error");
 69                 return false;
 70             }
 71             buf.assign(tmp,ret);
 72             return true;
 73         }
 74         //ssize_t sendto(int sockfd,const void* buf,size_t len,int flags,
 75         //struct sockaddr* dest_addr,socklen_t addrlen);
 76         //sockfd:套接字描述符
 77         //bu    f:要发送的数据
 78         //len:要发送的数据长度
 79         //flags:0--默认阻塞发送
 80         //dest_addr:目的端的地址信息--标识数据要发送到哪去
 81         //addrlen:地址信息长度
 82         //返回值:实际发送数据的长度  失败 -1
 83         bool SendTo(std::string& buf,struct sockaddr_in* daddr){
 84             socklen_t len=sizeof(struct sockaddr_in);
 85             int ret=sendto(_sock,buf.c_str(),buf.size(),0,(struct sockaddr*)daddr,len);
 86             if(ret<0){
 87                 perror("sendto error");
 88                 return false;
 89             }
 90             return true;
 91         }
 92         bool Close(){
 93             close(_sock);
 94             _sock=-1;
 95         }
 96     private:
 97         int _sock;
 98 
 99 };

UDP (客户端)

  1 #include "udpsocket.hpp"
  2 #define CHECK_RET(q) if((q)==false) return -1;
  3 int main(int argc,char* argv[]){
  4     if(argc!=3){
  5         printf("./udp_srv ip port\n");
  6         return -1;
  7     }
  8     //这个是服务端地址,为了让客户端知道数据请求发送到哪里去
  9     std::string ip=argv[1];
 10     uint16_t port=atoi(argv[2]);
  1 #include "udpsocket.hpp"
  2 #define CHECK_RET(q) if((q)==false) return -1;
  3 int main(int argc,char* argv[]){
  4     if(argc!=3){
  5         printf("./udp_srv ip port\n");
  6         return -1;
  7     }
  8     //这个是服务端地址,为了让客户端知道数据请求发送到哪里去
  9     std::string ip=argv[1];
 10     uint16_t port=atoi(argv[2]);
 11 
 12     UdpSocket sock;
 13     CHECK_RET(sock.Socket());
 14     //客户端并不推荐手动绑定地址
 15     //CHECK_RET(sock.Bind(ip,port));
 16     struct sockaddr_in srv_addr;
 17     srv_addr.sin_family=AF_INET;
 18     srv_addr.sin_port=htons(port);
 19     srv_addr.sin_addr.s_addr=inet_addr(ip.c_str());
 20 
 21     while(1){
 22         std::string buf;
 23         std::cout<<"clinet say:";
 24         fflush(stdout);
 25         std::cin >> buf;
 26         CHECK_RET(sock.SendTo(buf,&srv_addr));
 27         CHECK_RET(sock.RecvFrom(buf,&srv_addr));
 28         std::cout<<"serve say:"<<buf<<std::endl;
 29     }
 30     sock.Close();
 31     return 0;
 32 }

UDP(服务端)

  1 #include "udpsocket.hpp"
  2 #define CHECK_RET(q) if((q)==false) return -1;
  3 int main(int argc ,char* argv[]){
  4     if(argc!=3){
  5         perror("./udp_serve ip port\n");
  6         return -1;
  7     }
  8     std::string ip=argv[1];
  9     uint16_t port=atoi(argv[2]);
 10 
 11     UdpSocket sock;
 12     CHECK_RET(sock.Socket());
 13     CHECK_RET(sock.Bind(ip,port));
 14 
 15     while(1){
 16         std::string buf;
 17         struct sockaddr_in cli_addr;
 18         CHECK_RET(sock.RecvFrom(buf,&cli_addr));
 19         std::cout<<"clinet say:"<<buf<<std::endl;
 20         std::cout<<"serve say:";
 21         fflush(stdout);
 22         std::cin>>buf;
 23         CHECK_RET(sock.SendTo(buf,&cli_addr));
 24     }
 25     sock.Close();
 26 }

TCP(接口的封装)

  1 //创建套接字
  2 //bool Socket()
  3 //绑定地址信息
  4 //bool Bind(std::string& ip,uint16_t port)
  5 //服务端开始监听
  6 //bool Listen(iny backlog = 5)
  7 //客户端发起连接请求
  8 //bool Connect(std::string& ip ,uint16_t);
  9 //服务端已经获取已经连接成功的新建socket
 10 //bool Accept(TcpSocket& clisock,struct sockaddr_in* addr);
 11 //接收数据
 12 //bool Recv(std::string& buf)
 13 //发送数据
 14 //bool Send(std::string& buf)
 15 //关闭套接字
 16 //bool Close()
 17 #include<stdio.h>
 18 #include<errno.h>
 19 #include<stdlib.h>
 20 #include<string.h>
 21 #include<string>
 22 #include<unistd.h>
 23 #include<netinet/in.h>
 24 #include<arpa/inet.h>
 25 #include<sys/socket.h>
 26 
 27 #define CHECK_RET(q) if((q)==false) { return -1;}
 28 class TcpSocket{
 29     public :
 30         TcpSocket() : _sockfd(-1){}
 31         void SetSockFd(int newfd){
 32             _sockfd=newfd;
 33         }
 34         bool Socket(){
 35             _sockfd=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
 36             if(_sockfd<0){
 37                 perror("_socket error");
 38                 return false;
 39             }
 40             return true;
 41         }
 42         bool Bind(std::string& ip,uint16_t port){
 43             struct sockaddr_in addr;
 44             addr.sin_family=AF_INET;
 45             addr.sin_port=htons(port);
 46             addr.sin_addr.s_addr=inet_addr(ip.c_str());
 47             socklen_t len=sizeof(struct sockaddr_in);
 48             int ret=bind(_sockfd,(struct sockaddr*)&addr,len);
 49             if(ret<0){
 50                 perror("bind error");
 51                 return false;
 52             }
 53             return true;
 54         }
 55         bool Listen(int backlog=10){
 56             //int listen(int sockfd,int backlog);
 57             //backlog:
 58             //      最大并发连接数--内核当中已经完成连接的最大节点数
 59             int ret =listen(_sockfd,backlog);
 60             if(ret<0){
 61                 perror("listen error");
 62                 return false;
 63 
 64             }
 65             return true;
 66         }
 67         bool Connect(std::string& ip,uint16_t port){
 68             struct sockaddr_in addr;
 69             addr.sin_family=AF_INET;
 70             addr.sin_port=htons(port);
 71             addr.sin_addr.s_addr=inet_addr(ip.c_str());
 72             socklen_t len=sizeof(struct sockaddr_in);
 73             int ret=connect(_sockfd,(struct sockaddr*)&addr,len);
 74             if(ret<0){
 75                 perror("connect error");
 76                 return false;
 77             }
 78             return true;
 79         }
 80 
 81         bool Accept(TcpSocket& csock,struct sockaddr_in* addr=NULL ){
 82             //int accept(int sockfd,struct sockaddr* addr,socklen_t* len);
 83             //addr:客户端地址信息
 84             //len:输入输出型参数,既要指定接收长度,还是实际接收的长度
 85             //返回值:为新客户端新建socket套接字描述符
 86             //通过这个指定的描述符就可以与指定的客户端进行通信
 87             struct sockaddr_in _addr;
 88             socklen_t len=sizeof(struct sockaddr_in);
 89             int newfd=accept(_sockfd,(struct sockaddr*)&_addr,&len);
 90             if(newfd<0){
 91                 perror("newfd error");
 92                 return false;
 93             }
 94             if(addr!=NULL){
 95                 memcpy(addr,&_addr,len);
 96             }
 97             csock.SetSockFd(newfd);
 98             //_sockfd---仅用于接收新客户端的请求
 99            //newfd---专门用于与新客户端进行通信
100            return true;
101         }
102         bool Recv(std::string& buf){
103             char tmp[1024];
104 
105             //ssize_t recv(int sockfd,void* buf,size_t len,int flags);
106             //flags:0-默认阻塞接收  MSG_PEEK-获取数据但不从缓冲区移除
107             //返回值:实际接收数据长度 失败 -1  连接断开 0 
108             int ret=recv(_sockfd,tmp,1024,0);
109             if(ret<0){
110                 perror("recv error");
111                 return false;
112             }else if(ret==0){
113                 printf("peer shutdown");
114                 return false;
115             }
116             buf.assign(tmp,ret);
117             return true;
118         }
119         bool Send(std::string& buf){
120             //ssize_t send(int sockfd,void* buf,size_t len,int flags); 
121             int ret=send(_sockfd, buf.c_str(),buf.size(),0);
122             if(ret<0){
123                 perror("send error");
124                 return false;
125             }
126             return true;
127         }
128         bool Close(){
129             close(_sockfd);
130             _sockfd=-1;
131         }
132     private:
133         int _sockfd;
134 };

TCP(客户端)

 1 #include"tcpsocket.hpp"
  2 #include<iostream>
  3 int main(int argc,char* argv[]){
  4     if(argc!=3){
  5         printf("./tcp_cli ip port");
  6         return -1;
  7     }
  8     std::string ip=argv[1];
  9     uint16_t port=atoi(argv[2]);
 10 
 11     TcpSocket sock;
 12     CHECK_RET(sock.Socket());
 13     CHECK_RET(sock.Connect(ip,port));
 14 
 15     while(1){
 16 
 17         std::string buf;
 18         std::cout<<"client say:";
 19         fflush(stdout);
 20         std::cin>>buf;
 21         sock.Send(buf);
 22 
 23         buf.clear();
 24         sock.Recv(buf);
 25         std::cout<<"server say :"<<buf<<std::endl;
 26     }
 27     sock.Close();
 28     return 0;
 29 }

TCP(服务端)

  1 #include"tcpsocket.hpp"
  2 #include<iostream>
  3 int main(int argc,char* argv[]){
  4     if(argc!=3){
  5         printf("./tcp_srv ip port");
  6         return -1;
  7     }
  8     std::string ip=argv[1];
  9     uint16_t port=atoi(argv[2]);
 10     TcpSocket sock;
 11     CHECK_RET(sock.Socket());
 12     CHECK_RET(sock.Bind(ip,port));
 13     CHECK_RET(sock.Listen());
 14     while(1){
 15         TcpSocket clisock;
 16         struct sockaddr_in cliaddr;
 17         //accept是阻塞获取已完成的连接数
 18         if(sock.Accept(clisock,&cliaddr)==false){
 19             continue;
 20         }
 21         printf("new connect:%s : %d\n",inet_ntoa(cliaddr.sin_addr),ntohs(cliaddr.sin_port));
 22         std::string buf;
 23         clisock.Recv(buf);
 24         printf("client say:%s\n",buf.c_str());
 25         buf.clear();
 26         std::cout<<"server say:";
 27         fflush(stdout);
 28         std::cin>>buf;
 29         clisock.Send(buf);
 30     }
 31     sock.Close();
 32     return 0;
 33 }
           

TCP(多进程版本) 

 16 #include <iostream>
 17 #include <signal.h>
 18 #include <sys/wait.h>
 19 #include "tcpsocket.hpp"
 20 
 21 void sigcb(int no){
 22     while (waitpid(-1, NULL, WNOHANG) > 0);
 23 }
 24 int main(int argc, char *argv[])
 25 {
 26     if (argc != 3) {
 27         printf("./tcp_srv ip  port\n");
 28         return -1;
 29     }
 30 
 31     signal(SIGCHLD, sigcb);
 32     std::string ip = argv[1];
 33     uint16_t port = atoi(argv[2]);
 34 
 35     TcpSocket sock;
 36     CHECK_RET(sock.Socket());
 37     CHECK_RET(sock.Bind(ip, port));
 38     CHECK_RET(sock.Listen());
 39 
 40     while(1) {
 41         TcpSocket clisock;
 42         struct sockaddr_in cliaddr;
 43         //accept是阻塞获取已经完成的连接
 44         if (sock.Accept(clisock, &cliaddr) == false) {
 45             continue;
 46         }
 47         printf("new connect client:%s:%d\n",
 48                 inet_ntoa(cliaddr.sin_addr), ntohs(cliaddr.sin_port));
 49 
 50         int pid = fork();
 51         if (pid == 0) {
 52             while(1){
 53                 std::string buf;
 54                 clisock.Recv(buf);
 55                 printf("client say:%s\n", buf.c_str());
 56 
 57                 buf.clear();
 58                 std::cout<<"server say:";
 59                 fflush(stdout);
 60                 std::cin>>buf;
 61                 clisock.Send(buf);
 62             }
 63         }
 64         clisock.Close();
 65     }
 66     sock.Close();
 67     return 0;
 68 }
            

TCP(多线程版本)

  1 #include<iostream>
  2 #include<pthread.h>
  3 #include"tcpsocket.hpp"
  4 void* thr_start(void* arg){
  5     TcpSocket* sock=(TcpSocket*)arg;
  6     while(1){
  7         std::string buf;
  8         sock->Recv(buf);
  9         printf("client say: %s",buf.c_str());
 10 
 11         buf.clear();
 12         std::cout << "server say:";
 13         fflush(stdout);
 14         std::cin >> buf;
 15         sock->Send(buf);
 16 
 17     }
 18     sock->Close();
 19     delete sock;
 20     return NULL;
 21 }
 22 int main(int argc,char* argv[]){
 23     if(argc!=3){
 24         printf("./tcp_thread ip port");
 25         return -1;
 26     }
 27     std::string ip=argv[1];
 28     uint16_t port=atoi(argv[2]);
 29     TcpSocket sock;
 30     CHECK_RET(sock.Socket());
 31     CHECK_RET(sock.Bind(ip,port));
 32     CHECK_RET(sock.Listen());
 33 
 34     while(1){
 35         TcpSocket* clisock=new TcpSocket();
 36         struct sockaddr_in cliaddr;
 37         if(sock.Accept(*clisock,&cliaddr)==false){
 38             continue;
 39         }
 40         printf("new connect %s : %d",inet_ntoa(cliaddr.sin_addr),ntohs(cliaddr.sin_port));
 41         pthread_t tid;
 42         pthread_create(&tid,NULL,thr_start,(void*)clisock);
 43         pthread_detach(tid);
 44         //在多线程中,主线程不能关闭套接字,因为之间共享文件描述符表
 45         //如果在主线程中关闭socket 其他线程中的这个描述符也会被关闭
 46     }
 47     sock.Close();
 48     return 0;
 49 }

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值