基于TCP协议实现Linux下客户端与服务器之间的通信,实现多线程、多进程服务器

开发者福利!热门AI工具限时免费用 购周边即赠Coding Plan Lite,Claude Code、Cursor等20+工具畅享,效率翻倍! 阅读详情

TCP是TCP/IP协议族中一个比较重要的协议,这是一种可靠、建立链接、面向字节流的传输,工作在传输层。和TCP相对的不可靠、无链接、面向数据报的协议UDP,了解UDP客户端与服务器之间通信请戳UDP协议实现的服务器与客户端通信

TCP协议建立连接

首先我们通过一个大概的图来了解。
建立
建立连接首先必须是服务器启动,这没什么好说的,服务器为被动方,客户端为主动方,当客户端发起请求建立连接,服务器被动接受,经过上图三次握手建立连接,注意这三次连接都是在操作系统内部实现的。
那么我们就来介绍建立连接的相关API

socket获取通信的文件描述符。

#include <sys/socket.h>
int socket(int domain, int type, int protocol);

端口号的绑定

#include <sys/socket.h>
int bind(int sock, const struct sockaddr* address, socklen_t address_len);

这俩个API在UDP协议实现的服务器与客户端通信中有详细的参数返回值介绍。

作为服务器首先要进行监听

#include <sys/socket.h>
int listen(int socket, int backog);

参数介绍:
socket: 为socket函数返回的文件描述符
backlog: 建立连接过程中等待建立的请求个数
返回值:
成功返回0,失败返回-1;

这里我们再介绍这个backlog参数的含义:
这就相当与我们去银行取钱,到了发现人比较多,这个时候就需要坐在凳子上等,那么这里的凳子就是backlog的含义,就是现在最大的等待处理的个数。

接受请求:

#include <sys.socket.h>
int accept(int socket,  struct sockaddr* address, socklen_t* address_len);

参数:
socket:文件描述符
address:输出型参数,用来接受对方的IP 端口号,是一个结构体。
address_len:是一个输入输出型参数,输入进去为当前address的大小,输出为实际的大小。
返回值:
返回值成功为一个文件描述符,失败为-1;

这里要解释一下,socket不是已经创建出一个文件描述符,怎么还有?
accept的文件描述符,使用来直接进行数据的发送与收取,处理请求。
前面socket创建的文件描述符,在listen函数中用,是为了来接受请求.

举个例子:
socket创建的文件描述符,就像一个饭店,拉客人(listen函数)就是在外面进行监听,是否有客人要来饭店,当listen接受到客人,就会带到饭店,然后交给服务员(accept)来进行对客人吃饭请求的处理。这时候accpet就会是这个客人的请求的处理。

客户端连接函数:

#include <sys/socket.h>
int connect(int socketfd, const struct sockaddr* addr, socklen_t addrlen);

参数:
socketfd: 文件描述符;
addr :为要建立连接服务器的IP、端口号、使用网络协议IPV4;
addrlen:addr结构体的大小;
参数:
建立成功返回0,失败返回-1;

相关API介绍完我们开始实现一个简单的客户端与服务器

我们实现最简单的没有业务处理逻辑的通信,就把接受到的消息,发送给客户端

服务器

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>

void Response(int new_sock, struct sockaddr_in * client)
{
    while (1)
    {
        char buf[512] = {0};
        // 接受请求
        ssize_t rd = read(new_sock, buf, sizeof(buf)-1);
        if (rd < 0)
        {
            perror("read error\n");
            return;
        }
        if (rd == 0)
        {
            printf("read done!\n");
            return;
        }
        buf[rd] = '\0';
        // 处理请求
        printf("client say [%s:%d] # %s\n",inet_ntoa(client->sin_addr), ntohs(client->sin_port), buf);

        // response 响应
        write(new_sock, buf, strlen(buf));
    }
}

int main(int argc, char* argv[])
{
    if (argc != 3)
    {
        printf("usage:./server_tcp [ip] [port]");
        return 1;
    }

    int sock = socket(AF_INET, SOCK_STREAM, 0); // 文件描述符
    if (sock < 0)
    {
        perror("sock error\n");
        return 2;
    }

    // 绑定端口号
    struct sockaddr_in server;
    server.sin_family = AF_INET;
    server.sin_addr.s_addr = inet_addr(argv[1]);
    server.sin_port = htons(atoi(argv[2]));
    int b = bind(sock, (struct sockaddr*)&server, sizeof(server));
    if (b < 0)
    {
        perror("bind error\n");
        return 3;
    }

    // 监听
    int l = listen(sock, 3); // 最大的连接数量
    if (l < 0)
    {
        perror("listen error\n");
        return 4;
    }

    printf("bind and listen .... \n");

    // 接受请求处理
    struct sockaddr_in client;
    socklen_t len = sizeof(client);
    int new_sock = accept(sock, (struct sockaddr*)&client, &len);
    Response(new_sock, &client); // 处理函数
    return 0;
}

客户端:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>

int main(int argc, char* argv[])
{
    if (argc != 3)
    {
        perror("usage:./client_tcp [ip] [port]");
        return 1;
    }

    int sock = socket(AF_INET, SOCK_STREAM, 0);
    if (sock < 0)
    {
        perror("scoket error\n");
        return 2;
    }

    // 建立连接
    struct sockaddr_in server;
    server.sin_family = AF_INET;
    server.sin_addr.s_addr = inet_addr(argv[1]);
    server.sin_port = htons(atoi(argv[2]));
    socklen_t len = sizeof(server);
    int co = connect(sock, (struct sockaddr*)&server, len);
    if (co < 0)
    {
        perror("connect error\n");
        return 3;
    }

    while (1)
    {
        char buf[512] = {0};
        ssize_t rd = read(0, buf, sizeof(buf)-1);
        if (rd < 0)
        {
            perror("read error\n");
            return 4;
        }
        if (rd == 0)
        {
            printf("read done!\n");
            return 5;
        }
        buf[rd-1] = '\0';

        write(sock, buf, strlen(buf)); // 会阻塞的写与读

        ssize_t sockrd = read(sock, buf, sizeof(buf)-1);
        if (sockrd < 0)
        {
            perror("read error\n");
            return 4;
        }

        if (sockrd == 0)
        {
            printf("read done!\n");
            return 5;
        }

        buf[rd] = '\0';
        printf("server say # %s\n", buf);
    }
    return 0;
}

结果:
客户端
客户
服务器
server

TCP协议的的断开连接

建立连接需要三次交互,断开连接需要四次交互。
我们用图分析一下
断开
当数据发送完客户端调用close 这时候就会发送 FIN 服务器内核立刻恢复ACK 服务器再调用close 发送FIN 客户端回复ACK 进入等待。一段时间后退出。

基于TCP实现多线程、多进程服务器

代码戳
多进程TCP服务器
多线程TCP服务器

关于创建进程和创建线程
线程的创建
进程的创建

c/c++:基于TCP协议实现Linux客户端服务器之间通信实现多线程多进程服务器代码模板 目录 TCP协议Linux多进程服务器代码模板: TCP协议Linux多线程服务器代码模板: 客户端代码模板: TCP协议Linux多进程服务器代码模板: #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include... 阅读详情

相关推荐

基于linuxTCP网络聊天室设计实现

利用Linux实现基于TCP模式的网络聊天程序 主要完成的两大组成部分为:服务器客户端服务器程序主要负责监听客户端发来的消息。 客户端需要登录到服务器端才可以实现正常的聊天功能。该程序是利用进程以及共享内存来实现群发送消息的。 以下简单分析一下服务器端和客户端两个方面所要完成的任务。 服务器的主要功能如下:在特定的端口上进行监听,等待客户端的连接。 用户可以配置服务器端的监听端口。 向连

ReliaM的博客 3万+

多进程服务端和多客户端同时启动

服务端模拟多进程多线程并发;客户端可以同时开启多个,多线程模拟客户端;代码参考了网上(单个进程单线程服务端,单个客户端单线程)

LinuxTCP/IP网络编程示例——实现服务器/客户端通信(一)

一、说明 最近梳理网络编程的一些知识点时,整理了一些笔记,写了一些demo例程,主要包含下面几部分,后面会陆续完成。 1、LinuxTCP/IP网络编程示例——实现服务器/客户端通信(一):基于socket实现基本的服务器客户端通信,不支持多并发,即只支持一个客户端通信。 2、LinuxTCP/IP网络编程示例——实现服务器/客户端通信(二):基于socket实现基本的服务器客户端通信,不使用多进程/多线程和多路复用,实现服务端多并发功能。 3、LinuxTCP/IP网络编程示例——实现服务

Mr_XJC的博客 1万+

socket linux c & windows c# windows客户端服务器程序和linux客户端服务器程序。一共四个经典程序并有详细的注释。细细的阅读,一定会有收获。

windows客户端服务器程序和linux客户端服务器程序。一共四个经典程序并有详细的注释。细细的阅读,一定会有收获。

TCP服务器开发七步走(多线程

import socket import threading def request(a,b): while True: recv_data = conn_socket.recv(1024).decode('gbk') if recv_data: print(f'客户端ip:{ip_post}') print(f'数据:{recv_data}') conn_socket.send('信息收到,.

Alpha_mayfly的博客 260

30 张图解 | 高并发服务模型多线程多进程还是协程?

文章每周持续更新,原创不易,「三连」让更多人看到是对我最大的肯定。可以微信搜索公众号「 后端技术学堂 」第一时间阅读(一般比博客早更新一到两篇) 面试中经常会被问到高性能服务模型选择对比,以及如何提高服务性能和处理能力,这其中涉及操作系统软件和计算机硬件知识,其实都是在考察面试者的基础知识掌握程度,但如果没准备的话容易一头雾水,这次带大家从头到尾学习一遍,学完这一篇再也不怕面试官刨根问底了! 任务类型 谈高并发服务模型选择之前,我们先来看下程序的的任务类型,程序任务类型一般分为 CPU 密集型任务和 I.

程序员柠檬 1962

Linux_套接字(C++_TCP回显服务器——多进程/线程池(生产者消费者模型)处理多链接请求)

文章目录1.多进程版本服务端启动服务端客户端启动客户端本地测试2.多线程版本3.模板线程池版本线程池代码:设计任务Task.h服务端代码 1.多进程版本 这里选择创建子进程,让子进程再创建子进程。父进程等待子进程,子进程的子进程处理业务逻辑。因为子进程是直接退出,子进程的子进程变成孤儿进程被系统管理,所以父进程在等待的时候不是阻塞等待的,所以可以处理多条链接请求。 或者可以忽略SIGCHID信号让子进程不需要等待。 服务端 pragma once #include<iostream> #in

dodamce的博客 2343

(二)用多线程管理TCP多个客户端连接服务器

该程序的服务端大概工作逻辑如左图: 首先说说这个程序的作用:这个程序可用于多个客户端通过连接服务器来互相通信。如qq群聊。当一个客户端有信息发过来后,服务端就会通过客户端队列转发给其他客户端 先上代码: //TCP服务端 #include"myhead.h" struct client *head = NULL; struct sockaddr_in saddr; struct socka

ZJE 9606

TCP高性能服务器编程----多进程多线程

首先回忆一下在tcp编程中,主要看一下服务器端的代码 #include <stdio.h> #include <stdlib.h> #include <assert.h> #include <string.h> #include <unistd.h> #include <sys/socket.h> #include &lt...

w1216702236的博客 424

Linux网络】各版本TCP服务器构建 - 从理解到实现

本篇博文对【Linux网络】各版本TCP服务器构建 - 从理解到实现做了一个较为详细的介绍,不知道对你有没有帮助呢觉得博主写得还不错的三连支持下吧!会继续努力的~

2301_77954967的博客 1545

LinuxTCP多进程/多线程套接字通信

上篇文章简单的介绍了一下Linux下套接字通信的相关知识:  http://blog.csdn.net/qq_29503203/article/details/60961537 但是存在一个缺陷就是只能进行单进程通信,我们都知道实际上不可能一个服务器一次只能有一个客户端,所以在这里对其进行一个改进,我们通过fork出子进程去完成客户端发来的请求,而父进程只需用去accpet连接请求

qq_29503203的博客 4457

TCP网络通信多线程客户端服务器端)

比较牛逼的代码 ,多线程服务器客户端可以同时相互接受和发送数据。 另外还有详细的Linux 网络编程资料

LINUX下的一个多线程服务器客户端的网络传输程序

LINUX下的一个多线程服务器客户端的网络传输程序,初学者可以作为参考。 LINUX下的一个多线程服务器客户端的网络传输程序,初学者可以作为参考

linux】网络套接字编程(五)TCP服务器客户端实现——多进程版,多线程

一、多进程版 逻辑一 测试 逻辑二 测试 二、多线程版 测试 三、源代码 makefile TcpServer.hpp Main.cc TcpCilent.cc Log.hpp

重铸自身根基的博客 1466

TCP 服务器如何支持高并发?单进程、多进程多线程模型详解

本文介绍了TCP服务器编程的实现过程,从单进程到多进程再到多线程版本。主要内容包括:1)TCP服务器基本流程(socket-bind-listen-accept);2)单进程版实现及存在的问题(无法并发处理客户端);3)通过双fork技术实现多进程版,解决僵尸进程问题;4)使用信号处理优化多进程版本;5)多线程版本实现及类成员函数适配问题处理。文章通过餐厅接待客户的比喻形象解释了listenfd和sockfd的作用,对比了三种模型的并发能力、资源消耗和适用场景,帮助读者理解TCP服务器的核心设计思想。

2302_77620024的博客 4万+

04.基于C++实现多线程TCP服务器客户端通信

本项目实现了一个完整的TCP服务器客户端通信系统,涵盖了网络编程、多线程编程、线程池、守护进程、日志系统等多个核心知识点。通过模块化设计和面向对象编程,我们构建了一个结构清晰、功能完善的网络服务框架。实现HTTP/WebSocket等应用层协议集成数据库访问功能实现负载均衡和高可用设计探索异步I/O和协程技术网络编程是现代软件开发的基础技能,希望这个项目能够帮助你打开网络编程的大门,为你的技术成长提供坚实的基础。

youchou1274的博客 1605

Linux C语言TCP协议实战

TCPTCP涉及C语言部分相关函数讲解,基于TCP协议实现多进程服务器多线程服务器

2301_80754203的博客 4030

Linux 基于 TCP 协议的简单服务器-客户端应用

Linux 基于 TCP 协议的简单服务器-客户端应用

Han同学 1768

Linux网络编程】第六弹---构建TCP服务器:从基础到线程池版本的实现测试详解

TcpServerMain.cc;TcpServer.hpp:TcpServer类基本结构,构造析构函数,InitServer();Loop():Server 0(不靠谱版本),Server 1(多进程版本),Server 2(多线程版本),Server 3(线程池版本);TcpClientMain.cc;测试结果(4个版本);完整代码:Makefile,TcpClientMain.cc,TcpServer.hpp,TcpServerMain.cc~~~

小林熬夜学习编程的博客 4782
上一篇: 网络套接字socket,利用UDP协议实现服务器与客户端通信
下一篇: C++中STL中vector和list的迭代器失效问题
GangStudyIT
博客等级 码龄9年 46粉丝 73原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值