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

相关文章
|
16天前
|
机器学习/深度学习 人工智能 算法
植物病害识别系统Python+卷积神经网络算法+图像识别+人工智能项目+深度学习项目+计算机课设项目+Django网页界面
植物病害识别系统。本系统使用Python作为主要编程语言,通过收集水稻常见的四种叶片病害图片('细菌性叶枯病', '稻瘟病', '褐斑病', '稻瘟条纹病毒病')作为后面模型训练用到的数据集。然后使用TensorFlow搭建卷积神经网络算法模型,并进行多轮迭代训练,最后得到一个识别精度较高的算法模型,然后将其保存为h5格式的本地模型文件。再使用Django搭建Web网页平台操作界面,实现用户上传一张测试图片识别其名称。
66 21
植物病害识别系统Python+卷积神经网络算法+图像识别+人工智能项目+深度学习项目+计算机课设项目+Django网页界面
|
16天前
|
机器学习/深度学习 人工智能 算法
鸟类识别系统Python+卷积神经网络算法+深度学习+人工智能+TensorFlow+ResNet50算法模型+图像识别
鸟类识别系统。本系统采用Python作为主要开发语言,通过使用加利福利亚大学开源的200种鸟类图像作为数据集。使用TensorFlow搭建ResNet50卷积神经网络算法模型,然后进行模型的迭代训练,得到一个识别精度较高的模型,然后在保存为本地的H5格式文件。在使用Django开发Web网页端操作界面,实现用户上传一张鸟类图像,识别其名称。
60 12
鸟类识别系统Python+卷积神经网络算法+深度学习+人工智能+TensorFlow+ResNet50算法模型+图像识别
|
15天前
|
机器学习/深度学习 算法 TensorFlow
交通标志识别系统Python+卷积神经网络算法+深度学习人工智能+TensorFlow模型训练+计算机课设项目+Django网页界面
交通标志识别系统。本系统使用Python作为主要编程语言,在交通标志图像识别功能实现中,基于TensorFlow搭建卷积神经网络算法模型,通过对收集到的58种常见的交通标志图像作为数据集,进行迭代训练最后得到一个识别精度较高的模型文件,然后保存为本地的h5格式文件。再使用Django开发Web网页端操作界面,实现用户上传一张交通标志图片,识别其名称。
44 6
交通标志识别系统Python+卷积神经网络算法+深度学习人工智能+TensorFlow模型训练+计算机课设项目+Django网页界面
|
11天前
|
机器学习/深度学习 人工智能 算法
【新闻文本分类识别系统】Python+卷积神经网络算法+人工智能+深度学习+计算机毕设项目+Django网页界面平台
文本分类识别系统。本系统使用Python作为主要开发语言,首先收集了10种中文文本数据集("体育类", "财经类", "房产类", "家居类", "教育类", "科技类", "时尚类", "时政类", "游戏类", "娱乐类"),然后基于TensorFlow搭建CNN卷积神经网络算法模型。通过对数据集进行多轮迭代训练,最后得到一个识别精度较高的模型,并保存为本地的h5格式。然后使用Django开发Web网页端操作界面,实现用户上传一段文本识别其所属的类别。
24 1
【新闻文本分类识别系统】Python+卷积神经网络算法+人工智能+深度学习+计算机毕设项目+Django网页界面平台
|
6天前
|
网络协议 网络架构
网络协议介绍与学习
网络协议介绍与学习
20 4
|
6天前
|
网络协议 安全
网络中IP地址与域名系统
网络中IP地址与域名系统
21 3
|
6天前
|
网络协议 网络安全 数据安全/隐私保护
网络基础知识学习
如果你打算深入学习网络技术,建议从上述基础知识入手,并逐渐扩展到更高级的主题,如网络编程、网络安全、网络管理等。同时,实践是学习网络技术的关键,可以通过搭建自己的小型网络环境来进行实验和探索。
10 2
|
11天前
|
C++
【C++案例】一个项目掌握C++基础-通讯录管理系统
这篇文章通过一个通讯录管理系统的C++项目案例,详细介绍了如何使用C++实现添加、显示、删除、查找、修改和清空联系人等功能。
13 3
|
11天前
|
存储 安全 网络安全
云计算与网络安全:构建安全的数字生态系统## 一、
随着云计算技术的迅猛发展,网络安全问题日益凸显。本文探讨了云服务、网络安全和信息安全之间的紧密联系,分析了当前面临的主要挑战,并提出了相应的解决策略。通过深入剖析云计算环境中的安全问题,本文旨在为读者提供一个全面而清晰的认识,帮助大家更好地应对云计算时代的网络安全挑战。 ## 二、
|
11天前
|
机器学习/深度学习 人工智能 算法
【果蔬识别系统】Python+卷积神经网络算法+人工智能+深度学习+计算机毕设项目+Django网页界面平台
【果蔬识别系统】Python+卷积神经网络算法+人工智能+深度学习+计算机毕设项目+Django网页界面平台。果蔬识别系统,本系统使用Python作为主要开发语言,通过收集了12种常见的水果和蔬菜('土豆', '圣女果', '大白菜', '大葱', '梨', '胡萝卜', '芒果', '苹果', '西红柿', '韭菜', '香蕉', '黄瓜'),然后基于TensorFlow库搭建CNN卷积神经网络算法模型,然后对数据集进行训练,最后得到一个识别精度较高的算法模型,然后将其保存为h5格式的本地文件方便后期调用。再使用Django框架搭建Web网页平台操作界面,实现用户上传一张果蔬图片识别其名称。
31 0
【果蔬识别系统】Python+卷积神经网络算法+人工智能+深度学习+计算机毕设项目+Django网页界面平台
下一篇
无影云桌面