C/C++网络编程基础知识超详细讲解第三部分(系统性学习day13)

简介: C/C++网络编程基础知识超详细讲解第三部分(系统性学习day13)

一、并发服务器

1.进程并发服务器

消耗资源大,每连接进来一个客户端,你就要去开辟进程去服务那个客户端

           fork()

           举例:

if(fork()==0)  //子进程模块,不影响主进程中不断接收客户端连接
                        {
                            zhuanfa(&cfd);    
                        }

实例代码如下:

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
// struct sockaddr_in client;
// int len = sizeof(client);
 
void *zhuanfa(void *arg)
{
  int ret;
  int fd = *(int *)arg;
  char buf[1024];//接信息
  char buf1[50] = "猖狂,北伐!";
  while(1)
  {
 
    bzero(buf,sizeof(buf));
    ret = recv(fd,buf,sizeof(buf),0);
    if(0 == ret)
    {
      printf("客户%d离开了\n",fd);
      close(fd);
      return NULL;
    }else
     {
      printf("客户%d:%s\n",fd,buf); 
      // printf("客户%d进来了,IP地址为%s,端口号为%d\n",fd,inet_ntoa(client.sin_addr),ntohs(client.sin_port));
      send(fd,buf1,strlen(buf1),0); 
     }  
  }
  return NULL;
}
 
int main(void)
{
  //socket
  int serfd = socket(AF_INET,SOCK_STREAM,0);
  if(0>serfd)
  {
    perror("socket");
    return -1;
  }
  //bind
  struct sockaddr_in ser;//netinet/in.h
  ser.sin_family = AF_INET;
  ser.sin_port = htons(8888);
  ser.sin_addr.s_addr = inet_addr("192.168.10.5");
  if(bind(serfd,(struct sockaddr *)&ser,sizeof(ser))<0)
  {
    perror("bind");
    return -1;
  } 
  //listen
  listen(serfd,8);
  //accept
  int cfd;
  pthread_t a;
  while(1)
  {
    //不断接受不同的客户端,并分配一个服务员给客户对接,在线程进行通信
    cfd = accept(serfd,NULL,NULL);//accept保存客户信息到client
    // pthread_create(&a,NULL,zhuanfa,&cfd);
    // pthread_detach(a);
    if(fork()==0)
    {
      zhuanfa(&cfd);  
    }
  }
  return 0;
}

2.线程并发服务器

占用资源资源比较小,代码维护起来困难

           pthread_create  //线程的创建

           pthread_detach    //给创建线程能自动收尸的能力

           不自动:pthread_join

           

           printf("客户%d进来了,IP地址为%s,端口号为%d\n",fd,inet_ntoa(client.sin_addr),ntohs(client.sin_port));

           inet_ntoa(client.sin_addr) //网络二进制转回点分十进制

           ntohs(client.sin_port) //大端转小端

实例代码如下:

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
struct sockaddr_in client;
int len = sizeof(client);
void *zhuanfa(void *arg)
{
  int ret;
  int fd = *(int *)arg;
  char buf[1024];//接信息
  char buf1[50] = "注意绿色上网!";
  while(1)
  {
 
    bzero(buf,sizeof(buf));
    ret = recv(fd,buf,sizeof(buf),0);
    if(0 == ret)
    {
      printf("客户%d离开了\n",fd);
      close(fd);
      return NULL;
    }else
     {
      printf("客户%d:%s\n",fd,buf); 
      printf("客户%d进来了,IP地址为%s,端口号为%d\n",fd,inet_ntoa(client.sin_addr),ntohs(client.sin_port));
      send(fd,buf1,strlen(buf1),0); 
     }  
  }
  return NULL;
}
 
int main(void)
{
  //socket
  int serfd = socket(AF_INET,SOCK_STREAM,0);
  if(0>serfd)
  {
    perror("socket");
    return -1;
  }
  //bind
  struct sockaddr_in ser;//netinet/in.h
  ser.sin_family = AF_INET;
  ser.sin_port = htons(8888);
  ser.sin_addr.s_addr = inet_addr("192.168.10.5");
  if(bind(serfd,(struct sockaddr *)&ser,sizeof(ser))<0)
  {
    perror("bind");
    return -1;
  } 
  //listen
  listen(serfd,8);
  //accept
  int cfd;
  pthread_t a;
  while(1)
  {
    //不断接受不同的客户端,并分配一个服务员给客户对接,在线程进行通信
    cfd = accept(serfd,(struct sockaddr *)&client,&len);//accept保存客户信息到client
    pthread_create(&a,NULL,zhuanfa,&cfd);
    pthread_detach(a);
    
  }
  return 0;
}

二、域通信

优点:没网情况下照样能用客户端与服务器代码测试,模仿TCP/UDP

局限性:不能跨主机,只用于网络环境苛刻下的代码测试

区别:

               域通信:

                   struct sockaddr_un        <sys/un.h>

                       struct sockaddr_un{

                           sa_family_t   sin_family;   //地址族

                           char     sun_path[108];      //s套接字的路径千万要用strcpy赋值

                       };

                   s套接字,在bind后运行执行文件它就出现

域通信TCP实例代码如下:

服务器:

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/un.h>
#include <sys/select.h>
int main(void)
{
  //socket(变动)
  int sockfd = socket(AF_UNIX,SOCK_STREAM,0);//注意AF_UNIX
  if(0>sockfd)
  {
    perror("socket");
    return -1;
  }
  
  //bind(变动)
  struct sockaddr_un server;
  server.sun_family = AF_UNIX;
  strcpy(server.sun_path,"DJ");
  bind(sockfd,(struct sockaddr *)&server,sizeof(server));
  
  //listen
  listen(sockfd,8);
  
  //多路复用select
  int max = 0;
  int ret,cfd;//标志
  fd_set rfds;//读集合
  char buf[30];
  while(1)
  {
    FD_ZERO(&rfds);
    FD_SET(0,&rfds);
    FD_SET(sockfd,&rfds);
    max = sockfd;
    if(cfd>sockfd)//第一遍还没连接,这个判断没有作用
    {
      max=cfd;
      FD_SET(cfd,&rfds);
    }
    select(max+1,&rfds,NULL,NULL,NULL);
    if(FD_ISSET(0,&rfds))
    {
      bzero(buf,sizeof(buf));
      printf("0文件描述符触发\n");
      scanf("%s",buf);
      printf("键盘输入:%s\n",buf);
      if(cfd>3)//说明有人连接,改变了cfd一开始的值
      {
        send(cfd,buf,strlen(buf),0);
      }
    }else if(FD_ISSET(sockfd,&rfds))
     {
       cfd = accept(sockfd,NULL,NULL);
      if(0>cfd)
      {
        perror("accept");
        return -1;
      }
       printf("有客户连接进来了!\n");
     }else
      {
        bzero(buf,sizeof(buf));
        ret = recv(cfd,buf,sizeof(buf),0);
        if(0 == ret)
        {
        perror("recv");
        return -1; 
        }else
         {
           printf("客户说:%s\n",buf);
         } 
      }
  }
 
  return 0;
}

客户端:

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/un.h>
void *(recv_msg)(void *arg)
{
  int ret;
  int fd = *(int *)arg;
  char buf[50];
  while(1)
  {
    bzero(buf,sizeof(buf));
    ret = recv(fd,buf,sizeof(buf),0);
    if(0>ret)
    {
      perror("recv");
      return NULL;
    }else if(0 == ret)
     {
       printf("服务器离开了\n");
       return NULL;
     }else
       printf("服务器说:%s\n",buf);
  }
  return NULL;
}
int main(int argc,char *argv[])
{
  //变量区
  int clifd,ret;
  char buf[1024];
  pthread_t pid;
  
  //1>进行传参错误判断
  if(argc<2)//你运行时输入的个数   ./x a b 
  {
    printf("请输入<./可执行> <S_name> \n"); 
    return -1;
  }
  //2>创建socket套接字
  clifd = socket(AF_UNIX,SOCK_STREAM,0);
  if(clifd<0)
  {
    perror("socket");
    return -1;
  }
  printf("创建出的socket的值为%d\n",clifd);
  //3>声明s套接字
  struct sockaddr_un server;
  server.sun_family = AF_UNIX;
  strcpy(server.sun_path,(argv[1]));
#if 0
  if(bind(clifd,(struct sockaddr *)&server,sizeof(server))<0)
  {
    perror("bind");
    return -1;
  }
 
  //4>监听
  if(listen(clifd,8)<0)
  {
    perror("listen");
    return -1;
  }
  printf("监听已启动,保护服务器中^-^\n");
#endif
  //5>主动连接服务器
  if(connect(clifd,(struct sockaddr *)&server,sizeof(server))<0)
  {
    perror("connect");
    return -1;
  }
  printf("成功连接!\n");
  //开辟线程
  pthread_create(&pid,NULL,recv_msg,&clifd);
  pthread_detach(pid);
  
  //6>收发数据
  while(1)
  {
    bzero(buf,sizeof(buf));
    scanf("%s",buf);
    send(clifd,buf,strlen(buf),0);
  }
  //7>关闭套接字
  close(clifd);
  return 0;
}

补充说明:

注意:如果bind的错误提示,说地址已经占用

                   就用remove();清掉自己绑定的s套接字,再运行就没有

                   AF_UNIX

                       进程间通信有七种

                           早期:

                               1>无名管道

                               2>有名管道

                               3>信号

                           系统:

                               4>消息队列

                               5>共享内存

                               6>信号量

                           网络编程:

                               7>s套接字

               正常:

                   struct sockaddr_in

                   网络属性(IP地址和端口号)

                   AF_INET

三、广播与组播(UDP)

1.广播

         看图

       允许发送的广播的属性怎么设置

           #include<sys/types.h>

           #include<sys/socket.h>

           setsockopt

               int setsockopt(int sockfd,int level,int optname,const void * optval,socklen_t optlen);

               功能:

                   设置套接字的属性

               参数:

                   sockfd:套接字

                   level:等级

                   optname:属性名字

                   optval:属性的值

                   optlen:属性的长度

               返回值:

                   成功为0

                   失败返回-1,并设置错误码

           举例:

               1>允许发送的广播的属性

               int on = 1;//1>为生效值,0>不生效

               setsockopt(sockfd,SOL_SOCKET,SO_BROADCAST,&on,sizeof(on));

               2>允许重复用

               int on = 1;//1>为生效值,0>不生效

               setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on))

实例代码如下:

sendto:

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/un.h>
int main(void)
{
  int sockfd = socket(AF_INET,SOCK_DGRAM,0);
  if(0>sockfd)
  {
    perror("socket");
    return -1;
  }
  //设置发送广播属性
  int on = 1;//1>为生效值,0>不生效
  setsockopt(sockfd,SOL_SOCKET,SO_BROADCAST,&on,sizeof(on));
  
  struct sockaddr_in gb;
  gb.sin_family = AF_INET;
  gb.sin_port = htons(10086);
  gb.sin_addr.s_addr = inet_addr("192.168.10.255");
#if 0
  if(bind(sockfd,(struct sockaddr *)&gb,sizeof(gb))<0)
  {
    perror("bind");
    return -1;
  }
#endif  
  char buf[1024];
  // int addrlen = sizeof(gb);
  while(1)
  {
    bzero(buf,sizeof(buf));
    scanf("%s",buf);
    sendto(sockfd,buf,sizeof(buf),0,(struct sockaddr *)&gb,sizeof(gb));
    // printf("广播:%s\n",buf);
  }
  return 0;
}

recvfrom:

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/un.h>
int main(void)
{
  int sockfd = socket(AF_INET,SOCK_DGRAM,0);
  if(0>sockfd)
  {
    perror("socket");
    return -1;
  }
  
  struct sockaddr_in gb;
  gb.sin_family = AF_INET;
  gb.sin_port = htons(10086);
  gb.sin_addr.s_addr = inet_addr("192.168.10.255");
  if(bind(sockfd,(struct sockaddr *)&gb,sizeof(gb))<0)
  {
    perror("bind");
    return -1;
  }
  
  char buf[1024];
  int addrlen = sizeof(gb);
  while(1)
  {
    bzero(buf,sizeof(buf));
    recvfrom(sockfd,buf,sizeof(buf),0,(struct sockaddr *)&gb,&addrlen);
    printf("广播:%s\n",buf);
  }
  return 0;
}

2.组播

特定的广播,进一步细化成员

           看图

           多播组只有一个人,为单播;人多,就多播。

     

optval,————》ip-mreq{}     //与stuct sockaddr_in一个头文件netinet/in.h
            struct ip_mreq 
            {
                 struct  in_addr  imr_multiaddr;    //    组播地址    
                 struct  in_addr  imr_interface;    //自己linux的ip地址
            };
            struct in_addr{
                In_addr_t  s_addr;    //32位IPv4地址
            };
            举例:加入多播组
            struct ip_mreq zb;
            zb.imr_multiaddr.s_addr = inet_addr("233.233.233.233");
            zb.imr_interface.s_addr = inet_addr("192.168.10.5");
            setsockopt(sockfd,IPPROTO_IP,SO_ADD_MEMBERSHIP,&zb,sizeof(zb));

实例代码如下:

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/un.h>
int main(void)
{
  //1.socket
  int sockfd = socket(AF_INET,SOCK_DGRAM,0);
  if(0>sockfd)
  {
    perror("socket");
    return -1;
  }
  //2.运行发送广播
  int on = 1;//1>为生效值,0>不生效
  setsockopt(sockfd,SOL_SOCKET,SO_BROADCAST,&on,sizeof(on));
  //3.声明组播地址
  struct sockaddr_in zb;
  zb.sin_family = AF_INET;
  zb.sin_port = htons(9898);
  zb.sin_addr.s_addr = inet_addr("233.233.233.233");
  // if(bind(sockfd,(struct sockaddr *)&zb,sizeof(zb))<0)
  // {
    // perror("bind");
    // return -1; 
  // }
  //3.加入多播组
  // struct ip_mreq zb;
  // zb.imr_multiaddr.s_addr = inet_addr("233.233.233.233");
  // zb.imr_interface.s_addr = inet_addr("192.168.10.5");
  // setsockopt(sockfd,IPPROTO_IP,SO_ADD_MEMBERSHIP,&zb,sizeof(zb));
  //4.接收数据
  char buf[30];
  // int len = sizeof(zb);
  while(1)
  {
    bzero(buf,sizeof(buf));
    scanf("%s",buf);
    sendto(sockfd,buf,sizeof(buf),0,(struct sockaddr *)&zb,sizeof(zb));
    // printf("S:%s\n",buf);
  }
  return 0;
}
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/un.h>
int main(void)
{
  //1.socket
  int sockfd = socket(AF_INET,SOCK_DGRAM,0);
  if(0>sockfd)
  {
    perror("socket");
    return -1;
  }
  //2.bind组播地址
  struct sockaddr_in zb;
  zb.sin_family = AF_INET;
  zb.sin_port = htons(9898);
  zb.sin_addr.s_addr = inet_addr("233.233.233.233");
  if(bind(sockfd,(struct sockaddr *)&zb,sizeof(zb))<0)
  {
    perror("bind");
    return -1;  
  }
  //3.加入多播组
  struct ip_mreq db;
  db.imr_multiaddr.s_addr = inet_addr("233.233.233.233");
  db.imr_interface.s_addr = inet_addr("192.168.10.5");
  setsockopt(sockfd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&db,sizeof(db));
  //4.接收数据
  char buf[30];
  int len = sizeof(zb);
  while(1)
  {
    bzero(buf,sizeof(buf));
    recvfrom(sockfd,buf,sizeof(buf),0,(struct sockaddr *)&zb,&len);
    printf("S:%s\n",buf);
  }
  return 0;
}

四、图解如下


总结

关于C/C++网络编程基础知识超详细讲解第二部分的详解,懒大王就先分享到这里了,如果你认为这篇文章对你有帮助,请给懒大王点个赞点个关注吧,如果发现什么问题,欢迎评论区留言!!💕💕 💕

相关文章
|
9天前
|
存储
WGLOG日志管理系统可以采集网络设备的日志吗
WGLOG日志审计系统提供开放接口,支持外部获取日志内容后发送至该接口,实现日志的存储与分析。详情请访问:https://www.wgstart.com/wglog/docs9.html
|
3月前
|
小程序 UED
拓展校友网络的创新解决方案:校园论坛圈子小程序+跑腿+二手市场系统
这是一款基于小程序的校园跑腿服务平台,支持多种注册登录方式、下单支付、跑腿接单配送、订单跟踪评价及物流查询功能,并配备客服模块提升用户体验。系统包含用户、客服、物流、跑腿员和订单五大核心模块,功能完善。此外,平台还拓展了校友网络功能,如信息咨询发布、校园社区建设和活动组织等,旨在增强校友互动与联系,形成紧密的校友生态。
104 4
|
4月前
|
机器学习/深度学习 人工智能 算法
基于Python深度学习的【害虫识别】系统~卷积神经网络+TensorFlow+图像识别+人工智能
害虫识别系统,本系统使用Python作为主要开发语言,基于TensorFlow搭建卷积神经网络算法,并收集了12种常见的害虫种类数据集【"蚂蚁(ants)", "蜜蜂(bees)", "甲虫(beetle)", "毛虫(catterpillar)", "蚯蚓(earthworms)", "蜚蠊(earwig)", "蚱蜢(grasshopper)", "飞蛾(moth)", "鼻涕虫(slug)", "蜗牛(snail)", "黄蜂(wasp)", "象鼻虫(weevil)"】 再使用通过搭建的算法模型对数据集进行训练得到一个识别精度较高的模型,然后保存为为本地h5格式文件。最后使用Djan
296 1
基于Python深度学习的【害虫识别】系统~卷积神经网络+TensorFlow+图像识别+人工智能
|
5月前
|
机器学习/深度学习 人工智能 算法
基于Python深度学习的【蘑菇识别】系统~卷积神经网络+TensorFlow+图像识别+人工智能
蘑菇识别系统,本系统使用Python作为主要开发语言,基于TensorFlow搭建卷积神经网络算法,并收集了9种常见的蘑菇种类数据集【"香菇(Agaricus)", "毒鹅膏菌(Amanita)", "牛肝菌(Boletus)", "网状菌(Cortinarius)", "毒镰孢(Entoloma)", "湿孢菌(Hygrocybe)", "乳菇(Lactarius)", "红菇(Russula)", "松茸(Suillus)"】 再使用通过搭建的算法模型对数据集进行训练得到一个识别精度较高的模型,然后保存为为本地h5格式文件。最后使用Django框架搭建了一个Web网页平台可视化操作界面,
340 11
基于Python深度学习的【蘑菇识别】系统~卷积神经网络+TensorFlow+图像识别+人工智能
|
4月前
|
前端开发 Java 关系型数据库
基于ssm的网络直播带货管理系统,附源码+数据库+论文
该项目为网络直播带货网站,包含管理员和用户两个角色。管理员可进行主页、个人中心、用户管理、商品分类与信息管理、系统及订单管理;用户可浏览主页、管理个人中心、收藏和订单。系统基于Java开发,采用B/S架构,前端使用Vue、JSP等技术,后端为SSM框架,数据库为MySQL。项目运行环境为Windows,支持JDK8、Tomcat8.5。提供演示视频和详细文档截图。
123 10
|
5月前
|
机器学习/深度学习 编解码 测试技术
RT-DETR改进策略【模型轻量化】| 替换骨干网络为 2024轻量化网络MoblieNetV4:移动生态系统的通用模型
RT-DETR改进策略【模型轻量化】| 替换骨干网络为 2024轻量化网络MoblieNetV4:移动生态系统的通用模型
262 4
RT-DETR改进策略【模型轻量化】| 替换骨干网络为 2024轻量化网络MoblieNetV4:移动生态系统的通用模型
|
5月前
|
机器学习/深度学习 编解码 测试技术
YOLOv11改进策略【模型轻量化】| 替换骨干网络为 2024轻量化网络MoblieNetV4:移动生态系统的通用模型
YOLOv11改进策略【模型轻量化】| 替换骨干网络为 2024轻量化网络MoblieNetV4:移动生态系统的通用模型
455 8
YOLOv11改进策略【模型轻量化】| 替换骨干网络为 2024轻量化网络MoblieNetV4:移动生态系统的通用模型
|
5月前
|
存储 监控 算法
员工屏幕监控系统之 C++ 图像差分算法
在现代企业管理中,员工屏幕监控系统至关重要。本文探讨了其中常用的图像差分算法,该算法通过比较相邻两帧图像的像素差异,检测屏幕内容变化,如应用程序切换等。文中提供了C++实现代码,并介绍了其在实时监控、异常行为检测和数据压缩等方面的应用,展示了其实现简单、效率高的特点。
115 15
|
5月前
|
人工智能 网络协议 IDE
使用通义灵码AI高效学习muduo网络库开发指南
Muduo 是一个基于 C++11 的高性能网络库,支持多线程和事件驱动,适用于构建高效的服务器和应用程序。它提供 TCP/IP 协议支持、异步非阻塞 I/O、定时器、异步日志等功能,并具备跨平台特性。通过 Git 克隆 muduo 仓库并切换至 C++17 分支可开始使用。借助 AI 工具如 Deepseak-v3,用户可以更便捷地学习和理解 Muduo 的核心模块及编写测试用例,提升开发效率。
|
5月前
|
搜索推荐 数据挖掘
优质网络舆情监测系统大盘点
一款出色的网络舆情监测系统,不仅能够助力相关主体迅速捕捉舆情信息,有效应对危机,还能够助力其更好地把握舆论动态,维护自身形象。那么,市场上有哪些比较好的网络舆情监测系统呢?这里,本文有为各位整理了一些好用的舆情检测系统,以供各位参考!
198 0