Linux——多进程服务器与客户端并发通信

简介: Linux——多进程服务器与客户端并发通信

运用知识


套接字相关函数socket()、bind()、listen()、connect()、accept()、recv()、send()、select()、close()


https://blog.csdn.net/weixin_45525272/article/details/107732407


atoi


atoi (表示 ascii to integer)是把字符串转换成整型数的一个函数,应用在计算机程序和办公软件中。int atoi(const char *nptr)函数会扫描参数 nptr字符串,会跳过前面的空白字符(例如空格,tab缩进)等。如果 nptr不能转换成 int 或者 nptr为空字符串,那么将返回 0 。特别注意,该函数要求被转换的字符串是按十进制数理解的。atoi输入的字符串对应数字存在大小限制(与int类型大小有关),若其过大可能报错-1。


htons


htons是将整型变量从主机字节顺序转变成网络字节顺序, 就是整数在地址空间存储方式变为高位字节存放在内存的低地址处。


bzero()函数


原型:extern void bzero(void *s, int n);


参数说明:s 要置零的数据的起始地址;


n 要置零的数据字节个数。


用法:#include <string.h>


功能:置字节字符串s的前n个字节为零且包括‘\0’。


说明:bzero无返回值,并且使用string.h头文件,string.h曾经是posix标准的一部分,但是在POSIX.1-2001标准里面,这些函数被标记为了遗留函数而不推荐使用。在POSIX.1-2008标准里已经没有这些函数了。推荐使用memset替代bzero。


代码示例



服务器


/*************************************************************************
    > File Name: server_fork.c
    > Author: 杨永利
    > Mail: 1795018360@qq.com 
    > Created Time: 2020年08月01日 星期六 10时02分04秒
 ************************************************************************/
#include <stdio.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <strings.h>
int main(int argc, char* argv[]){
  if (argc!=2)
  {
    /* code */
    printf("参数错误!\n");
    return -1;
  }
  // 第一步 创建套接字描述符
  int server_socket=socket(PF_INET,SOCK_STREAM,0);
  //第二步 创建服务器地址结构
    struct sockaddr_in server_addr;
    bzero(&server_addr, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(atoi(argv[1]));
    //INADDR_ANY就是指定地址为0.0.0.0的地址,这个地址事实上表示不确定地址,或“所有地址”、“任意地址”。 一般来说,在各个系统中均定义成为0值。
    server_addr.sin_addr.s_addr = /*htonl()*/INADDR_ANY;
    // 第三步 绑定套接字
    if (bind(server_socket, (struct sockaddr*)&server_addr, sizeof(server_addr)))
    {
      /* code */
      printf("绑定套接字失败!\n");
      return -1;
    }
    // 第四步 监听套接字
    if (listen(server_socket,10))
    {
      /* code */
      printf("监听套接字失败!\n");
      return -1;
    }
    // 第五步 多进程连接
    struct sockaddr_in client_addr;
    int client_addr_size=sizeof(client_addr);
    while(1)
    {
      int client_socket=0;
      bzero(&client_addr,sizeof(client_addr));
      if((client_socket = accept(server_socket, (struct sockaddr*)&client_addr, &client_addr_size)) == -1)
      {
          printf("接收客户端失败!\n-----client_socket=%d",client_socket);
          return -1;
      }
      // 创建子进程 fork()
      /*
      负值:创建子进程失败。
      零:返回到新创建的子进程。
      正值:返回父进程或调用者。该值包含新创建的子进程的进程ID
      */
      int pid=fork();
      // 创建新的子进程成功
      if (pid==0)
      {
        // 创建临时客户端地址结构体用于存放开始accept到的客户端数据
        struct sockaddr_in client_in_addr;
        client_in_addr.sin_addr.s_addr=client_addr.sin_addr.s_addr;
        client_in_addr.sin_port=client_addr.sin_port;
        printf("来了一个新的客户端,ip是:%s,端口:%d\n", inet_ntoa(client_addr.sin_addr),client_in_addr.sin_port);
        // 关闭当前进程的套接字描述符,
        close(server_socket);
            char buf[1024];
            int recv_len;
            while(1)
            {
              bzero(buf, sizeof(buf));
                if((recv_len = recv(client_socket, buf, sizeof(buf), 0)) < 0)
                    return -1;
                // 判断如果接收到为0就有个客户端退出,跳出循环
                if(!recv_len){
                    printf("有客户端退出了,ip:%s 端口:%d\n", inet_ntoa(client_in_addr.sin_addr),client_in_addr.sin_port);//struct in_addr
                  break;
                }
                printf("客户端-%s -%d 对我说:%s\n",inet_ntoa(client_in_addr.sin_addr),client_in_addr.sin_port,buf);
              if(send(client_socket, buf, strlen(buf), 0) <= 0)
                    return -1;
            }
            close(client_socket);
            return 0;
      }
      // 返回给父进程子进程id  父进程就可以关闭接收的套接字描述符
        else if(pid > 0)
        {
            close(client_socket);
        }
        else
        //创建子进程失败,直接退出
           exit(-1);
    }
    return 0;
}


客户端


/*************************************************************************
    > File Name: client.c
    > Author: 杨永利
    > Mail: 1795018360@qq.com 
    > Created Time: 2020年08月01日 星期六 10时01分47秒
 ************************************************************************/
#include <stdio.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <strings.h>
int main(int argc, char* argv[]){
  if (argc != 3)
  {
    printf("参数错误!\n");
    return -1;
  }
  // 第一步创建网络通信套接字描述符
  int client_socket=socket(AF_INET,SOCK_STREAM,0);
  // 第二步创建服务器的地址结构体
  struct sockaddr_in server_addr;
  bzero(&server_addr,sizeof(server_addr));
  server_addr.sin_family=AF_INET;
  server_addr.sin_port=htons(atoi(argv[2]));
  server_addr.sin_addr.s_addr=inet_addr(argv[1]);
  // 第三步 连接服务器
  if (connect(client_socket,(struct sockaddr*)&server_addr,sizeof(server_addr))==-1)
  {
    /* code */
    printf("连接服务器失败!\n");
    return -1;
  }
  printf("连接服务器成功!\n");
  char message[1024];
  bzero(message,sizeof(message));
  char buf[1024];
  printf("我是客户端,我将给服务器发送内容\n");
  printf("如果希望聊天退出,请输入q或者Q:\n");
  while(1)
  {
    printf("我发送给服务器的:\n");
    scanf("%s",buf);
    if (strlen(buf)==1)
    {
      if(buf[0] == 'q' || buf[0] == 'Q')
                break;
    }
    if(strlen(buf) != write(client_socket, buf, strlen(buf))){
            printf("write() error!\n");
            exit(-1);
        }
        if(read(client_socket, message, sizeof(message)) <= 0){
            printf("read() error!\n");
            return -1;
        }
        printf("服务器对我说:%s\n", message);
        bzero(buf, sizeof(buf));
        bzero(message, sizeof(message));
  }
  close(client_socket);
  printf("服务器关闭了!\n");
    return 0;
}
相关文章
|
弹性计算 安全 Linux
阿里云服务器ECS安装宝塔Linux面板、安装网站(新手图文教程)
本教程详解如何在阿里云服务器上安装宝塔Linux面板,涵盖ECS服务器手动安装步骤,包括系统准备、远程连接、安装命令执行、端口开放及LNMP环境部署,手把手引导用户快速搭建网站环境。
|
监控 Linux 网络安全
FinalShell SSH工具下载,服务器管理,远程桌面加速软件,支持Windows,macOS,Linux
FinalShell是一款国人开发的多平台SSH客户端工具,支持Windows、Mac OS X和Linux系统。它提供一体化服务器管理功能,支持shell和sftp同屏显示,命令自动提示,操作便捷。软件还具备加速功能,提升访问服务器速度,适合普通用户和专业人士使用。
4223 0
|
数据挖掘 Linux 数据库
服务器数据恢复—Linux系统服务器数据恢复案例
服务器数据恢复环境: linux操作系统服务器中有一组由4块SAS接口硬盘组建的raid5阵列。 服务器故障: 服务器工作过程中突然崩溃。管理员将服务器操作系统进行了重装。 用户方需要恢复服务器中的数据库、办公文档、代码文件等。
|
JavaScript Linux Python
在Linux服务器中遇到的立即重启后的绑定错误:地址已被使用问题解决
总的来说,解决"地址已被使用"的问题需要理解Linux的网络资源管理机制,选择合适的套接字选项,以及合适的时间点进行服务重启。以上就是对“立即重启后的绑定错误:地址已被使用问题”的全面解答。希望可以帮你解决问题。
856 20
|
存储 开发工具 git
[Git] 深入理解 Git 的客户端与服务器角色
Git 的核心设计理念是分布式,每个仓库既可以是客户端也可以是服务器。通过 GitHub 远程仓库和本地仓库的协作,Git 实现了高效的版本管理和代码协作。GitHub 作为远程裸仓库,存储项目的完整版本历史并支持多客户端协作;本地仓库则通过 `.git` 文件夹独立管理版本历史,可在离线状态下进行提交、回滚等操作,并通过 `git pull` 和 `git push` 与远程仓库同步。这种分布式特性使得 Git 在代码协作中具备强大的灵活性和可靠性。
[Git] 深入理解 Git 的客户端与服务器角色
|
人工智能 搜索推荐 程序员
用 Go 语言轻松构建 MCP 客户端与服务器
本文介绍了如何使用 mcp-go 构建一个完整的 MCP 应用,包括服务端和客户端两部分。 - 服务端支持注册工具(Tool)、资源(Resource)和提示词(Prompt),并可通过 stdio 或 sse 模式对外提供服务; - 客户端通过 stdio 连接服务器,支持初始化、列出服务内容、调用远程工具等操作。
3386 5
|
网络协议 开发者 Python
Socket如何实现客户端和服务器间的通信
通过上述示例,展示了如何使用Python的Socket模块实现基本的客户端和服务器间的通信。Socket提供了一种简单且强大的方式来建立和管理网络连接,适用于各种网络编程应用。理解和掌握Socket编程,可以帮助开发者构建高效、稳定的网络应用程序。
835 10
|
消息中间件 Linux C++
c++ linux通过实现独立进程之间的通信和传递字符串 demo
的进程间通信机制,适用于父子进程之间的数据传输。希望本文能帮助您更好地理解和应用Linux管道,提升开发效率。 在实际开发中,除了管道,还可以根据具体需求选择消息队列、共享内存、套接字等其他进程间通信方
520 16
|
存储 运维 监控
深度体验阿里云系统控制台:SysOM 让 Linux 服务器监控变得如此简单
作为一名经历过无数个凌晨三点被服务器报警电话惊醒的运维工程师,我对监控工具有着近乎苛刻的要求。记得去年那次大型活动,我们的主站流量暴增,服务器内存莫名其妙地飙升到90%以上,却找不到原因。如果当时有一款像阿里云 SysOM 这样直观的监控工具,也许我就不用熬通宵排查问题了。今天,我想分享一下我使用 SysOM 的亲身体验,特别是它那令人印象深刻的内存诊断功能。
886 1
|
Linux 虚拟化 Docker
Linux服务器部署docker windows
在当今软件开发中,Docker成为流行的虚拟化技术,支持在Linux服务器上运行Windows容器。流程包括:1) 安装Docker;2) 配置支持Windows容器;3) 获取Windows镜像;4) 运行Windows容器;5) 验证容器状态。通过这些步骤,你可以在Linux环境中顺利部署和管理Windows应用,提高开发和运维效率。
2832 1

热门文章

最新文章