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;
}
相关文章
|
16天前
|
安全 Java 数据处理
Python网络编程基础(Socket编程)多线程/多进程服务器编程
【4月更文挑战第11天】在网络编程中,随着客户端数量的增加,服务器的处理能力成为了一个重要的考量因素。为了处理多个客户端的并发请求,我们通常需要采用多线程或多进程的方式。在本章中,我们将探讨多线程/多进程服务器编程的概念,并通过一个多线程服务器的示例来演示其实现。
|
1月前
|
消息中间件 Unix Linux
Linux进程间通信(IPC)介绍:详细解析IPC的执行流程、状态和通信机制
Linux进程间通信(IPC)介绍:详细解析IPC的执行流程、状态和通信机制
55 1
|
1月前
|
XML 前端开发 JavaScript
探索 XMLHttpRequest:网页与服务器的异步通信之道(上)
探索 XMLHttpRequest:网页与服务器的异步通信之道(上)
|
2月前
|
消息中间件 运维 网络协议
客户端和服务器之间的通信
客户端和服务器之间的通信
34 0
|
1月前
|
存储 Shell Linux
【Shell 命令集合 文件传输 FTP客户端工具】Linux ncftp 命令使用指南
【Shell 命令集合 文件传输 FTP客户端工具】Linux ncftp 命令使用指南
40 0
|
20天前
|
网络协议 Python
pythonTCP客户端编程连接服务器
【4月更文挑战第6天】本教程介绍了TCP客户端如何连接服务器,包括指定服务器IP和端口、发送连接请求、处理异常、进行数据传输及关闭连接。在Python中,使用`socket`模块创建Socket对象,然后通过`connect()`方法尝试连接服务器 `(server_ip, server_port)`。成功连接后,利用`send()`和`recv()`进行数据交互,记得在通信完成后调用`close()`关闭连接,确保资源释放和程序稳定性。
|
2天前
|
JSON JavaScript 前端开发
服务器通信:使用WebSocket与后端实时交互
【4月更文挑战第24天】WebSocket为解决服务器与客户端实时双向通信问题而生,常用于聊天、游戏和实时通知等场景。本文通过4步教你实现WebSocket通信:1) 客户端使用JavaScript创建WebSocket连接;2) 监听`open`、`message`和`close`事件;3) 使用`send`方法发送数据;4) 使用`close`方法关闭连接。服务器端则需处理连接和数据发送,具体实现依后端技术而定。WebSocket为现代Web应用的实时交互提供了强大支持。
|
11天前
|
网络协议 Ubuntu Unix
Linux 下使用 socket 实现 TCP 客户端
Linux 下使用 socket 实现 TCP 客户端
|
1月前
|
消息中间件 Linux API
跨进程通信设计:Qt 进程间通讯类全面解析
跨进程通信设计:Qt 进程间通讯类全面解析
81 0
|
1月前
|
消息中间件 并行计算 网络协议
探秘高效Linux C/C++项目架构:让进程、线程和通信方式助力你的代码飞跃
探秘高效Linux C/C++项目架构:让进程、线程和通信方式助力你的代码飞跃
34 0