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

相关文章
|
7天前
|
机器学习/深度学习 人工智能 算法
猫狗宠物识别系统Python+TensorFlow+人工智能+深度学习+卷积网络算法
宠物识别系统使用Python和TensorFlow搭建卷积神经网络,基于37种常见猫狗数据集训练高精度模型,并保存为h5格式。通过Django框架搭建Web平台,用户上传宠物图片即可识别其名称,提供便捷的宠物识别服务。
118 55
|
1月前
|
监控 安全 Linux
在 Linux 系统中,网络管理是重要任务。本文介绍了常用的网络命令及其适用场景
在 Linux 系统中,网络管理是重要任务。本文介绍了常用的网络命令及其适用场景,包括 ping(测试连通性)、traceroute(跟踪路由路径)、netstat(显示网络连接信息)、nmap(网络扫描)、ifconfig 和 ip(网络接口配置)。掌握这些命令有助于高效诊断和解决网络问题,保障网络稳定运行。
72 2
|
17天前
|
机器学习/深度学习 人工智能 算法
【宠物识别系统】Python+卷积神经网络算法+深度学习+人工智能+TensorFlow+图像识别
宠物识别系统,本系统使用Python作为主要开发语言,基于TensorFlow搭建卷积神经网络算法,并收集了37种常见的猫狗宠物种类数据集【'阿比西尼亚猫(Abyssinian)', '孟加拉猫(Bengal)', '暹罗猫(Birman)', '孟买猫(Bombay)', '英国短毛猫(British Shorthair)', '埃及猫(Egyptian Mau)', '缅因猫(Maine Coon)', '波斯猫(Persian)', '布偶猫(Ragdoll)', '俄罗斯蓝猫(Russian Blue)', '暹罗猫(Siamese)', '斯芬克斯猫(Sphynx)', '美国斗牛犬
99 29
【宠物识别系统】Python+卷积神经网络算法+深度学习+人工智能+TensorFlow+图像识别
|
3天前
|
数据采集 监控 安全
公司网络监控软件:Zig 语言底层优化保障系统高性能运行
在数字化时代,Zig 语言凭借出色的底层控制能力和高性能特性,为公司网络监控软件的优化提供了有力支持。从数据采集、连接管理到数据分析,Zig 语言确保系统高效稳定运行,精准处理海量网络数据,保障企业信息安全与业务连续性。
18 4
|
29天前
|
安全 Windows
【Azure Cloud Service】在Windows系统中抓取网络包 ( 不需要另外安全抓包工具)
通常,在生产环境中,为了保证系统环境的安全和纯粹,是不建议安装其它软件或排查工具(如果可以安装,也是需要走审批流程)。 本文将介绍一种,不用安装Wireshark / tcpdump 等工具,使用Windows系统自带的 netsh trace 命令来获取网络包的步骤
69 32
|
26天前
|
弹性计算 监控 数据库
制造企业ERP系统迁移至阿里云ECS的实例,详细介绍了从需求分析、数据迁移、应用部署、网络配置到性能优化的全过程
本文通过一个制造企业ERP系统迁移至阿里云ECS的实例,详细介绍了从需求分析、数据迁移、应用部署、网络配置到性能优化的全过程,展示了企业级应用上云的实践方法与显著优势,包括弹性计算资源、高可靠性、数据安全及降低维护成本等,为企业数字化转型提供参考。
52 5
|
1月前
|
存储 数据可视化 API
重磅干货,免费三方网络验证[用户系统+CDK]全套API接口分享教程。
本套网络验证系统提供全面的API接口,支持用户注册、登录、数据查询与修改、留言板管理等功能,适用于不想自建用户系统的APP开发者。系统还包含CDK管理功能,如生成、使用、查询和删除CDK等。支持高自定义性,包括20个自定义字段,满足不同需求。详细接口参数及示例请参考官方文档。
|
1月前
|
数据库连接 Go 数据库
Go语言中的错误注入与防御编程。错误注入通过模拟网络故障、数据库错误等,测试系统稳定性
本文探讨了Go语言中的错误注入与防御编程。错误注入通过模拟网络故障、数据库错误等,测试系统稳定性;防御编程则强调在编码时考虑各种错误情况,确保程序健壮性。文章详细介绍了这两种技术在Go语言中的实现方法及其重要性,旨在提升软件质量和可靠性。
30 1
|
1月前
|
网络协议 网络安全 网络虚拟化
本文介绍了十个重要的网络技术术语,包括IP地址、子网掩码、域名系统(DNS)、防火墙、虚拟专用网络(VPN)、路由器、交换机、超文本传输协议(HTTP)、传输控制协议/网际协议(TCP/IP)和云计算
本文介绍了十个重要的网络技术术语,包括IP地址、子网掩码、域名系统(DNS)、防火墙、虚拟专用网络(VPN)、路由器、交换机、超文本传输协议(HTTP)、传输控制协议/网际协议(TCP/IP)和云计算。通过这些术语的详细解释,帮助读者更好地理解和应用网络技术,应对数字化时代的挑战和机遇。
87 3
|
1月前
|
机器学习/深度学习 人工智能 算法
基于Python深度学习的【垃圾识别系统】实现~TensorFlow+人工智能+算法网络
垃圾识别分类系统。本系统采用Python作为主要编程语言,通过收集了5种常见的垃圾数据集('塑料', '玻璃', '纸张', '纸板', '金属'),然后基于TensorFlow搭建卷积神经网络算法模型,通过对图像数据集进行多轮迭代训练,最后得到一个识别精度较高的模型文件。然后使用Django搭建Web网页端可视化操作界面,实现用户在网页端上传一张垃圾图片识别其名称。
79 0
基于Python深度学习的【垃圾识别系统】实现~TensorFlow+人工智能+算法网络
下一篇
DataWorks