C(C++)网络编程(服务器单线程)

打印 上一主题 下一主题

主题 1667|帖子 1667|积分 5001

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
详细先容如何在 C/C++ 中使用 TCP 协议实现客户端和服务器之间的网络通信。网络编程在当代软件开发中非常重要,尤其是开发分布式系统、实时应用程序或客户端-服务器架构时,掌握 TCP 网络通信的根本知识和操作流程是必不可少的。
目次


  • 网络通信的底子知识
  • TCP 协议简介
  • 客户端与服务器端的通信流程
  • 代码案例解说

    • 客户端代码
    • 服务器端代码

  • 总结

1. 网络通信的底子知识

网络通信指的是两台或多台计算机通过网络互相传递数据的过程。通常有两种通信模式:


  • 面向连接的通信(如 TCP)
  • 无连接的通信(如 UDP)
在面向连接的通信中,双方在发送数据之前首先需要建立一个可靠的连接。TCP 就是面向连接的协议,它确保数据的传输是可靠的。
2. TCP 协议简介

TCP(Transmission Control Protocol,传输控制协议) 是一种面向连接的、可靠的、基于字节流的协议。在 TCP 协议中,数据的传输过程如下:

  • 建立连接:客户端和服务器端举行三次握手,建立可靠的连接。
  • 数据传输:在连接建立之后,数据以流的方式举行传输,TCP 会确保数据的完备性温和序。
  • 断开连接:通信竣过后,双方通过四次挥手断开连接。
3. 客户端与服务器端的通信流程

TCP 通信一般分为两部门:服务器端客户端


  • 服务器端

    • 创建套接字(socket)
    • 绑定 IP 地点和端口号
    • 监听连接哀求
    • 接受客户端的连接
    • 举行数据的收发
    • 关闭连接

  • 客户端

    • 创建套接字
    • 连接到服务器
    • 举行数据的收发
    • 关闭连接

下面我们将通过代码案例来详细阐明每一步的实现。
4. 代码案例解说

4.1 客户端代码

客户端的功能主要是连接服务器,并向服务器发送数据。以下是一个简单的客户端代码示例:

用于通信的布局体界说:

  1. [/code] [code]#include<iostream>
  2. #include<cstring>
  3. #include<arpa/inet.h>
  4. #include<unistd.h>
  5. #include<stdlib.h>
  6. //客户端代码
  7. int main() {
  8.     // 1. 创建通信的套接字
  9.     int fd_lis = socket(AF_INET, SOCK_STREAM, 0);
  10.     if(fd_lis == -1) {
  11.         perror("socket_listen error!");
  12.         return -1;
  13.     }
  14.     // 2. 链接服务器的IP和端口
  15.     struct sockaddr_in saddr;
  16.     saddr.sin_family = AF_INET;
  17.     saddr.sin_port = htons(9999);
  18.     inet_pton(AF_INET, "192.168.159.129", &saddr.sin_addr.s_addr);
  19.     // 3. 连接服务器
  20.     int ret = connect(fd_lis, (struct sockaddr*)&saddr, sizeof(saddr));
  21.     if(ret == -1) {
  22.         perror("connect_error");
  23.         return -1;
  24.     }
  25.     // 4. 开始通信
  26.     int number = 0;
  27.     while (1) {
  28.         std::cout << "客户端发送了信息" << std::endl;
  29.         char buff[1024];
  30.         sprintf(buff, "你好,hello world,%d...\n", number++);
  31.         send(fd_lis, &buff, sizeof(buff), 0);
  32.         memset(buff, 0, sizeof(buff));
  33.         int len = recv(fd_lis, &buff, sizeof(buff), 0);
  34.         if(len > 0) {
  35.             std::cout << "server says: " << buff << std::endl;
  36.         } else if (len == 0) {
  37.             // 通信结束
  38.             break;
  39.         } else {
  40.             perror("recv_error");
  41.             break;
  42.         }
  43.         sleep(1);
  44.     }
  45.     // 5. 关闭套接字
  46.     close(fd_lis);
  47.     return 0;
  48. }
复制代码

客户端代码阐明:


  • 创建套接字:socket() 函数用于创建套接字,使用 IPV4 协议(AF_INET),流式传输(SOCK_STREAM),并指定使用 TCP 协议(0)。
  • 指定服务器地点和端口:struct sockaddr_in 用于指定服务器的 IP 地点和端口,htons(9999) 将端口号转为网络字节序,inet_pton 函数将字符串形式的 IP 地点转换为二进制形式。
  • 连接服务器:connect() 函数用于连接到服务器。
  • 发送和吸取数据:send() 函数发送数据,recv() 函数用于吸取服务器端返回的数据。
  • 关闭套接字:close() 关闭套接字,断开连接。
字节序和函数功能不清楚的,可以检察套接字-Socket | 爱编程的大丙。老师写的非常清楚,B站的课程也讲的十分清楚。
4.2 服务器端代码

服务器端的功能是接受客户端的连接哀求,并举行通信。以下是服务器端的代码示例:
  1. #include<iostream>
  2. #include<string>
  3. #include<arpa/inet.h>
  4. #include<unistd.h>
  5. //服务器端
  6. int main(){
  7.     // 1:创建监听的套接字  具体参数含义为:使用IPV4地址,采用流式传输,使用TCP协议。 返回监听的文件描述符
  8.     int fd_lis=socket(AF_INET,SOCK_STREAM,0);
  9.     if(fd_lis==-1){
  10.         perror("socket_listen error!");
  11.         return -1;
  12.     }
  13.     // 2:绑定本地IP和端口 (IP和端口是addr结构体) 该结构体指定地址类型,通信端口和IP地址
  14.     struct sockaddr_in saddr;
  15.     saddr.sin_family=AF_INET;
  16.     saddr.sin_port=htons(9999);
  17.     //INADDR_ANY 使用宏定义的0地址,能够自动读取服务器的网卡IP地址
  18.     saddr.sin_addr.s_addr=INADDR_ANY;
  19.     int ret = bind(fd_lis,(struct sockaddr*)&saddr,sizeof(saddr));
  20.     if(ret==-1){
  21.         perror("bing _error");
  22.         return -1;
  23.     }
  24.     // 3设置监听 (监听的文件描述符,一次最大监听的访问量)
  25.     ret=listen(fd_lis,128);
  26.     if(ret==-1){
  27.         perror("listen _error");
  28.         return -1;
  29.     }
  30.     // 4 阻塞并等待客户端的链接,该结构体存储来自客户端的端口和地址
  31.     struct sockaddr_in caddr;
  32.     caddr.sin_family=AF_INET;
  33.     caddr.sin_port=INADDR_ANY;
  34.     int addrlen=sizeof(caddr);
  35.     int fd_acp=accept(fd_lis,(struct sockaddr*)&caddr,(socklen_t*)&addrlen);
  36.    
  37.     if(fd_acp==-1){
  38.         perror("accept _error");
  39.         return -1;
  40.     }else{
  41.         //打印端口,客户端的IP和端口号
  42.         char ip_arrd[32];
  43.         std::cout<<"客户端ip地址:"<<inet_ntop(AF_INET,&caddr.sin_addr.s_addr,ip_arrd,sizeof(ip_arrd))<<std::endl;
  44.         std::cout<<"客户端端口号:"<<ntohs(caddr.sin_port)<<std::endl;
  45.     }
  46.    
  47.     // 5:开始通信
  48.     while (1)
  49.     {
  50.         char buff[1024];
  51.         int len=recv(fd_acp,&buff,sizeof(buff),0);
  52.         if(len>0){
  53.             std::cout<<"client says:"<<buff<<std::endl;
  54.             send(fd_acp,buff,sizeof(buff),0);
  55.         }else if (len==0)
  56.         {
  57.             //通信结束
  58.             break;
  59.         }else{
  60.             perror("accept_error");
  61.             break;
  62.         }
  63.     }
  64.         close(fd_lis);
  65.         close(fd_acp);
  66.     return 0;
  67. }
复制代码

服务器端代码阐明:


  • 创建套接字:与客户端雷同,socket() 函数创建监听套接字。
  • 绑定 IP 和端口:使用 bind() 函数绑定本地 IP 和端口。INADDR_ANY 可以自动获取服务器的 IP 地点。
  • 监听连接:listen() 函数开始监听端口,允许多个客户端连接。
  • 接受连接:accept() 函数阻塞等待客户端的连接哀求,并返回一个新的文件形貌符,用于与客户端通信。
  • 通信过程:使用 recv() 吸取客户端发送的数据,使用 send() 将数据返回给客户端。
  • 关闭套接字:通信竣过后,关闭文件形貌符,断开连接。



免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

汕尾海湾

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表