TCP服务器的演变过程:多进程实现一对多的TCP服务器

这篇具有很好参考价值的文章主要介绍了TCP服务器的演变过程:多进程实现一对多的TCP服务器。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、前言

手把手教你从0开始编写TCP服务器程序,体验开局一块砖,大厦全靠垒。

为了避免篇幅过长使读者感到乏味,对【TCP服务器的开发】进行分阶段实现,一步步进行优化升级。本节在上一章节的基础上,改为多进程方式实现TCP服务器,为每个新接入的客户端分配进程,实现一个服务器程序处理多个客户端连接。主要目的是比较不同方式的利弊关系。

二、新增使用的fork()函数

函数原型:

#include <unistd.h>
pid_t fork(void);

fork()通过复制调用进程来创建一个新进程。新进程被称为子进程。调用进程被称为父进程。

子进程和父进程在单独的内存空间中运行。在执行fork()时,两个内存空间都具有相同的内容。其中一个进程执行的内存写入、文件映射(mmap)和取消映射(munmap),不会影响另一个进程。

返回值:

  • 返回0,代表子进程。
  • 返回非零,代表是父进程。

三、实现步骤

使用多进程方案,来一个连接请求则克隆一个子进程。

(1)创建socket。

int listenfd=socket(AF_INET,SOCK_STREAM,0);
if(listenfd==-1){
    printf("errno = %d, %s\n",errno,strerror(errno));
    return SOCKET_CREATE_FAILED;
}

(2)绑定地址。

struct sockaddr_in server;
memset(&server,0,sizeof(server));

server.sin_family=AF_INET;
server.sin_addr.s_addr=htonl(INADDR_ANY);
server.sin_port=htons(LISTEN_PORT);

if(-1==bind(listenfd,(struct sockaddr*)&server,sizeof(server))){
    printf("errno = %d, %s\n",errno,strerror(errno));
    close(listenfd);
    return SOCKET_BIND_FAILED;
}

(3)设置监听。

if(-1==listen(listenfd,BLOCK_SIZE)){
   printf("errno = %d, %s\n",errno,strerror(errno));
   close(listenfd);
   return SOCKET_LISTEN_FAILED;
}

(4)接收连接。

struct sockaddr_in client;
memset(&client,0,sizeof(client));
socklen_t len=sizeof(client);
    
int clientfd=accept(listenfd,(struct sockaddr*)&client,&len);
if(clientfd==-1){
    printf("errno = %d, %s\n",errno,strerror(errno));
    close(listenfd);
    return SOCKET_ACCEPT_FAILED;
}

(5)为每个连接克隆子进程。

pid_t pid=fork();
if(pid==0)
{
     routine(clientfd);
     break;
}
else
{
     printf("pid = %d\n",pid);
}

(6)在子进程里面接收数据。

char buf[BUFFER_LENGTH]={0};
ret=recv(clientfd,buf,BUFFER_LENGTH,0);
if(ret==0) {
     printf("connection dropped\n");

}
printf("recv --> %s\n",buf);

(7)在子进程里面发送数据。

if(-1==send(clientfd,buf,ret,0))
{
    printf("errno = %d, %s\n",errno,strerror(errno));
}

(8)关闭文件描述符。

close(listenfd);

四、完整代码

#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>

#include <errno.h>
#include <string.h>
#include <unistd.h>

#include <pthread.h>

#define LISTEN_PORT     8888
#define BLOCK_SIZE      10
#define BUFFER_LENGTH   1024

enum ERROR_CODE{
    SOCKET_CREATE_FAILED=-1,
    SOCKET_BIND_FAILED=-2,
    SOCKET_LISTEN_FAILED=-3,
    SOCKET_ACCEPT_FAILED=-4
};

void routine(int clientfd)
{
    while(1)
    {
        // 5.
        char buf[BUFFER_LENGTH]={0};
        int ret=recv(clientfd,buf,BUFFER_LENGTH,0);
        if(ret==0) {
            printf("connection dropped\n");
            break;
        }
        
        printf("fd=%d recv --> %s\n",clientfd,buf);
        send(clientfd,buf,ret,0);
        
    }
    

    close(clientfd);
}

int main(int argc,char **argv)
{
    // 1.
    int listenfd=socket(AF_INET,SOCK_STREAM,0);
    if(listenfd==-1){
        printf("errno = %d, %s\n",errno,strerror(errno));
        return SOCKET_CREATE_FAILED;
    }

    // 2.
    struct sockaddr_in server;
    memset(&server,0,sizeof(server));

    server.sin_family=AF_INET;
    server.sin_addr.s_addr=htonl(INADDR_ANY);
    server.sin_port=htons(LISTEN_PORT);

    if(-1==bind(listenfd,(struct sockaddr*)&server,sizeof(server))){
        printf("errno = %d, %s\n",errno,strerror(errno));
        close(listenfd);
        return SOCKET_BIND_FAILED;
    }

    // 3.
    if(-1==listen(listenfd,BLOCK_SIZE)){
        printf("errno = %d, %s\n",errno,strerror(errno));
        close(listenfd);
        return SOCKET_LISTEN_FAILED;
    }

    printf("listen port: %d\n",LISTEN_PORT);
    struct sockaddr_in client;
    socklen_t len=sizeof(client);
    int clientfd=-1;
    
    while(1)
    {
        // 4.
        memset(&client,0,sizeof(client));
        clientfd=accept(listenfd,(struct sockaddr*)&client,&len);
        if(clientfd==-1){
            printf("errno = %d, %s\n",errno,strerror(errno));
            continue;
        }

        printf("accept successdul, fd = %d\n",clientfd);
        pid_t pid=fork();
        if(pid==0)
        {
            routine(clientfd);
            break;
        }
        else
        {
            printf("pid = %d\n",pid);
        }
    }

    
    close(listenfd);

    return 0;
}

编译:

gcc -o server server.c

五、TCP客户端

5.1、自己实现一个TCP客户端

自己实现一个TCP客户端连接TCP服务器的代码:

#include <stdio.h>
#include <sys/socket.h>

#include <netinet/in.h>
#include <arpa/inet.h>

#include <errno.h>
#include <string.h>

#include <unistd.h>
#include <stdlib.h>

#define BUFFER_LENGTH   1024

enum ERROR_CODE{
    SOCKET_CREATE_FAILED=-1,
    SOCKET_CONN_FAILED=-2,
    SOCKET_LISTEN_FAILED=-3,
    SOCKET_ACCEPT_FAILED=-4
};

int main(int argc,char** argv)
{
    if(argc<3)
    {
        printf("Please enter the server IP and port.");
        return 0;
    }
    printf("connect to %s, port=%s\n",argv[1],argv[2]);

    int connfd=socket(AF_INET,SOCK_STREAM,0);
    if(connfd==-1)
    {
        printf("errno = %d, %s\n",errno,strerror(errno));
        return SOCKET_CREATE_FAILED;

    }
    struct sockaddr_in serv;
    serv.sin_family=AF_INET;
    serv.sin_addr.s_addr=inet_addr(argv[1]);
    serv.sin_port=htons(atoi(argv[2]));
    socklen_t len=sizeof(serv);
    int rwfd=connect(connfd,(struct sockaddr*)&serv,len);
    if(rwfd==-1)
    {
        printf("errno = %d, %s\n",errno,strerror(errno));
        close(rwfd);
        return SOCKET_CONN_FAILED;
    }
    int ret=1;
    while(ret>0)
    {
        char buf[BUFFER_LENGTH]={0};
        printf("Please enter the string to send:\n");
        scanf("%s",buf);
        send(connfd,buf,strlen(buf),0);

        memset(buf,0,BUFFER_LENGTH);
        printf("recv:\n");
        ret=recv(connfd,buf,BUFFER_LENGTH,0);
        printf("%s\n",buf);
        
    }
    close(rwfd);
    return 0;
}

编译:

gcc -o client client.c

5.2、Windows下可以使用NetAssist的网络助手工具

TCP服务器的演变过程:多进程实现一对多的TCP服务器,Linux网络设计,服务器,tcp/ip,网络,多进程,linux,网络协议,c语言
下载地址:http://old.tpyboard.com/downloads/NetAssist.exe

小结

这里基于上一个章节的内容进行了升级,可以接受多个客户端同时连接,并为每个连接克隆一个子进程进行通信。

但是,使用多进程会非常消耗资源,特别是高并发的时候,会是系统内存爆满,开销巨大。那么有没有办法在一个线程中就可以完成高并发通信呢?答案是可以的,下一章节将介绍使用select实现一个线程完成多个连接的通信,也就是IO多路复用技术。
TCP服务器的演变过程:多进程实现一对多的TCP服务器,Linux网络设计,服务器,tcp/ip,网络,多进程,linux,网络协议,c语言文章来源地址https://www.toymoban.com/news/detail-762225.html

到了这里,关于TCP服务器的演变过程:多进程实现一对多的TCP服务器的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • TCP服务器的演变过程:使用epoll构建reactor网络模型实现百万级并发(详细代码)

    手把手教你从0开始编写TCP服务器程序,体验开局一块砖,大厦全靠垒。 为了避免篇幅过长使读者感到乏味,对【TCP服务器的开发】进行分阶段实现,一步步进行优化升级。 本节,在上一章节介绍了如何使用epoll开发高效的服务器,本节将介绍使用epoll构建reactor网络模型,实

    2024年02月01日
    浏览(75)
  • TCP服务器的演变过程:C++使用libevent库开发服务器程序

    手把手教你从0开始编写TCP服务器程序,体验开局一块砖,大厦全靠垒。 为了避免篇幅过长使读者感到乏味,对【TCP服务器的开发】进行分阶段实现,一步步进行优化升级。 在上一章节介绍了如何使用epoll构建reactor网络模型开发高效的服务器,有了上一节的基础,本节将介绍

    2024年01月23日
    浏览(53)
  • 【TCP/IP】多进程服务器的实现(进阶) - 多进程服务器模型及代码实现

             经过前面的铺垫,我们已经具备实现并发服务器的基础了,接下来让我们尝试将之前的单任务回声服务器改装成多任务并发模式吧!         在编写代码前,先让我们大致将多任务(回声)服务器的模型抽象一下,如下图所示:         当客户端请求服务(

    2024年02月08日
    浏览(150)
  • TCP服务器实现—多进程版,多线程版,线程池版

    目录 前言 1.存在的问题 2.多进程版 3.多线程版 4.线程池版 总结         在上一篇文章中使用TCP协议实现了一个简单的服务器,可以用来服务端和客户端通信,但是之前的服务器存在一个问题,就是当有多个客户端连接服务器的时候,服务器只能和一个客户端通信,其它的客

    2024年02月12日
    浏览(47)
  • 【TCP/IP】多进程服务器的实现(进阶) - 进程的概念及fork函数

    目录 进程的概念及应用 进程的定义 进程的ID fork函数(进程创建函数)         多进程(以及多线程)是现代计算机网络的精髓。在之前,我们所做的诸如回声服务器、回声客户端、文件收发等都是偏向基础的单进程应用。而经过前面的铺垫,我们对Socket也有了一定了解

    2024年02月09日
    浏览(55)
  • 【TCP/IP】多进程服务器的实现(进阶) - 僵尸进程及wait、waitpid函数

    目录 僵尸(Zombie)进程 僵尸进程的产生机制 僵尸进程的危害 僵尸进程的销毁 wait函数 waitpid函数          进程管理在网络编程中十分重要,如果未处理好,将会导致出现“僵尸进程”,进而影响服务器端对进程的管控。         第一次听到这个名词大家可能会有些陌生

    2024年02月09日
    浏览(43)
  • [Linux] 网络编程 - 初见TCP套接字编程: 实现简单的单进程、多进程、多线程、线程池tcp服务器

    网络的上一篇文章, 我们介绍了网络变成的一些重要的概念, 以及 UDP套接字的编程演示. 还实现了一个简单更简陋的UDP公共聊天室. [Linux] 网络编程 - 初见UDP套接字编程: 网络编程部分相关概念、TCP、UDP协议基本特点、网络字节序、socket接口使用、简单的UDP网络及聊天室实现…

    2024年02月16日
    浏览(66)
  • 多进程并发TCP服务器模型(含客户端)(网络编程 C语言实现)

    摘要 :大家都知道不同pc间的通信需要用到套接字sockte来实现,但是服务器一次只能收到一个客户端发来的消息,所以为了能让服务器可以接收多个客户端的连接与消息的传递,我们就引入了多进程并发这样一个概念。听名字就可以知道--需要用到进程,当然也有多线程并发

    2024年02月17日
    浏览(67)
  • 【TCP/IP】多进程服务器的实现(进阶) - 信号处理及signal、sigaction函数

    目录 信号 signal函数 sigaction函数 用信号来处理僵尸进程          在之前我们学习了如何处理“僵尸进程”,不过可能也会有疑问:调用wait和waitpid函数时我们关注的始终是在子进程上,那么在父进程上如何实现对子进程的管控呢?为此,我们引入一个概念——信号处理。

    2024年02月08日
    浏览(61)
  • 网络通信(13)-C#TCP服务器和客户端同时在一个进程实现的实例

    有时项目需求中需要服务器和客户端同时在一个进程实现,一边需要现场接收多个客户端的数据,一边需要将数据汇总后发送给远程服务器。下面通过实例演示此项需求。 C#TCP服务器和客户端同时在一个进程实现的实例如下: 界面设计 UI文件代码

    2024年01月22日
    浏览(65)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包