TCP的客户端、服务器端socket编程

本文详细介绍了TCP套接字编程的过程,包括socket创建、客户端连接、服务器端绑定与监听、数据收发及关闭套接字等步骤。通过示例代码展示了如何在C++中实现TCP客户端和服务端的交互,并强调了客户端通常不需要绑定端口的原因。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

使用TCP套接字编程可以实现基于TCP/IP协议的面向连接的通信,它分为服务器端和客户端两部分,其主要实现过程如下 :
在这里插入图片描述
1、socket函数

无论是客户端还是服务器端,都需要创建一个socket,该函数返回socket标识符。socket是一个结构体,被创建在内核中。

sockfd=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);   //AF_INT:ipv4, SOCK_STREAM:tcp协议

2、connect函数
客户端创建了socket后,需要和服务器端建立连接,此时使用connect函数和服务器端进行连接。

connect(sockfd,(struct sockaddr*)&serveraddr,sizeof(serveraddr))

3、bind函数
把一个本地协议地址和套接口绑定,比如把192.168.198.128的8000端口绑定到套接口。

为什么在上图客户端不推荐绑定?
这是因为如果没有调用bind函数绑定一个端口的话,当调用connect函数时,内核会为该套接口临时选定一个端口,因此可以不用绑定。而服务器之所以需要绑定的原因就是,所以客户端都需要知道服务器使用的哪个端口,所以需要提前绑定。

bind(sockfd,(struct sockaddr*)&serveraddr,sizeof(serveraddr))

4、listen函数
调用linsten函数后,内核将从该套接口接收连接请求。backlog代表服务端在同一时间能处理的最大连接数。

listen(sockfd,backlog)

5、accept函数
此函数返回新建连接的描述符。

注意:
此处的套接口不同于服务器开始创建的监听套接口,此套接口是已经完成连接的套接口,监听套接口只是用来监听。

accept(sockfd,(struct sockaddr*)&clientaddr,&clientaddr_len);

6、close函数
数据传输完成后,需要关闭套接口

close(fd);

代码
tcpsocket.hpp

    1 #include <cstdio>                                                                                                                                                 
    2 #include <iostream>
    3 #include <string>
    4 #include<string.h>
    5 #include <unistd.h>
    6 #include <arpa/inet.h>
    7 #include <netinet/in.h>
    8 #include <sys/socket.h>
    9 #define CHECK_RET(q) if((q)==false){return -1;}
   10 #define LISTEN_BACKLOG 5
   11 using namespace std;
   12 
   13 class TcpSocket
   14 {
   15   private:
   16     int _sockfd;
   17   public:
   18     TcpSocket()
   19       :_sockfd(-1)
   20     {}
   21 
   22     bool Socket()
   23     {
   24       _sockfd=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
   25       if(_sockfd<0)
   26       {
   27         perror("sockfd error");
   28         return false;
   29       }
   30       return true;
   31     }
   32 
   33     bool Bind(const string& ip,const uint16_t port)
   34     {
   35       struct sockaddr_in addr;
   36       addr.sin_family=AF_INET;
   37       addr.sin_port=htons(port);
   38       addr.sin_addr.s_addr=inet_addr(&ip[0]);
   39       socklen_t len = sizeof(struct sockaddr_in);
   40       int ret = bind(_sockfd,(struct sockaddr*)&addr,len);
   41       if(ret<0)
   42       {
   43         perror("bind error");
   44         return false;
   45       }
   46       return true;
   47     }
   48 
   49     bool Listen(int backlog=LISTEN_BACKLOG)
   50     {
   51       int ret = listen(_sockfd,backlog);
   52       if(ret<0)
   53       {
   54         perror("listen error");
   55         return false;
   56       }
   57       return true;
   58     }
   59 
   60     bool Connect(const string& ip,const int port)
   61     {
   62       struct sockaddr_in addr;
   63       addr.sin_family=AF_INET;                                                                                                                                    
   64       addr.sin_port=htons(port);
   65       addr.sin_addr.s_addr=inet_addr(&ip[0]);
   66       socklen_t len = sizeof(struct sockaddr_in);
   67       int ret= connect(_sockfd,(struct sockaddr*)&addr,len);
   68       if(ret<0)
   69       {
   70         perror("connect error");
   71         return false;
   72       }
   73       return true;
   74     }
   75 
   76     bool Accept(TcpSocket* sock,string* ip=NULL,uint16_t* port=NULL)
   77     {
   78 
   79       struct sockaddr_in addr;
   80       socklen_t len = sizeof(struct sockaddr_in);
   81       int newfd=accept(_sockfd,(struct sockaddr*)&addr,&len);
   82       if(newfd<0)
   83       {
   84         perror("accept error");
   85         return false;
   86       }
   87       sock->_sockfd=newfd;
   88       if(ip!=NULL)
   89       {
   90         *ip=inet_ntoa(addr.sin_addr);
   91       }
   92       if(port!=NULL)
   93       {
   94         *port=ntohs(addr.sin_port);
   95       }
   96       return true;
   97     }                                                                                                                                                             
   98 
   99     bool Recv(string* buf)
  100     {
  101       char tmp[1024]={0};
  102       int ret =recv(_sockfd,tmp,1024,0);
  102       int ret =recv(_sockfd,tmp,1024,0);
  103       if(ret<0)
  104       {
  105         perror("recv error");
  106         return false;
  107       }
  108       else if(ret==0)
  109       {
  110         printf("peer shutdown");
  111         return false;
  112       }
  113       buf->assign(tmp,ret);
  114       return true;
  115     }
  116 
  117     bool Send(const string& data)
  118     {
  119       int total=0;
  120 
  121       while(total<data.size())
  122       {
  123         int ret = send(_sockfd,&data[0]+total,data.size()-total,0);
  124         if(ret<0)
  125         {
  126           perror("send error");
  127           return false;
  128         }
  129         total+=ret;
  130       }
  131       return true;
  132     }
  133     bool Close()
  134     {
  135       if(_sockfd!=-1)
  136       {
  137         close(_sockfd);
  138       }
  139       return true;
  140     }
  141 
  142 };

thread_srv.cpp

  1 #include "tcpsocket.hpp"                                                                                                                                            
  2 #include <signal.h>
  3 #include <sys/wait.h>
  4 #include<cstdlib>
  5 #include<pthread.h>
  6 using namespace std;
  7 void *thr_entry(void* arg)
  8 {
  9   TcpSocket* clisock=(TcpSocket*)arg;
 10   bool ret;
 11   while(1)
 12   {
 13     string buf;
 14     ret = clisock->Recv(&buf);
 15     if (ret == false)
 16     {
 17       clisock->Close();
 18       delete clisock;
 19       return NULL;
 20     }
 21     cout << "client say: " << buf << endl;
 22     buf.clear();
 23     cout << "server say: ";
 24     cin >> buf;
 25     ret = clisock->Send(buf);
 26     if (ret == false)
 27     {
 28       clisock->Close();
 29       delete clisock;
 30       return NULL;
 31     }
 32   }
 33   clisock->Close();
 34   delete clisock;
 35   return NULL;
 36 }
 37 
 38 int main(int argc, char *argv[])
 39 {
 40   if (argc != 3)
 41   {
 42     printf("usage: ./tcp_src192.168.189.128  8000\n");
 43     return -1;
 44   }
 45   signal(SIGCHLD,SIG_IGN);
 46   string srvip = argv[1];
 47   uint16_t srvport = stoi(argv[2]);
 48   TcpSocket lst_sock;
 49   CHECK_RET(lst_sock.Socket());
 50   CHECK_RET(lst_sock.Bind(srvip, srvport));
 51   CHECK_RET(lst_sock.Listen());
 52   while(1) 
 53   {
 54     TcpSocket* clisock=new TcpSocket();
 55     string cliip;
 56     uint16_t cliport;
 57     bool ret = lst_sock.Accept(clisock, &cliip,&cliport);
 58     if (ret == false) 
 59     {
 60       continue;
 61 
 62     }
 63     cout<<"get newcon:"<< cliip<<"-"<<cliport<<"\n";
 64 
 65     pthread_t tid;
 66     pthread_create(&tid,NULL,thr_entry,(void*)clisock);
 67     pthread_detach(tid);
 68 
 69   }
 70 
 71   lst_sock.Close();
 72 }                        

tcp_cli.cpp

  1 #include "tcpsocket.hpp"                                                                                                                                            
  2 using namespace std;
  3 int main(int argc,char* argv[])
  4 {
  5   if(argc!=3)
  6   {
  7     printf("usage: ./tcp_cli srvip srvport\n");
  8     return -1;
  9   }
 10   string srvip=argv[1];
 11   uint16_t srvport = stoi(argv[2]);
 12   TcpSocket cli_sock;
 13   CHECK_RET(cli_sock.Socket());
 14   CHECK_RET(cli_sock.Connect(srvip,srvport));
 15   while(1)
 16   {
 17     string buf;
 18     cout<<"客户端:";
 19     cin>>buf;
 20     CHECK_RET(cli_sock.Send(buf));
 21     buf.clear();
 22     CHECK_RET(cli_sock.Recv(&buf));
 23     cout<<"服务端:"<<buf<<endl;
 24   }
 25   CHECK_RET(cli_sock.Close());
 26   return 0;
 27 
 28 }
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值