【高并发网络通信架构】1.Linux下实现单客户连接的tcp服务端

news2024/11/13 10:54:09

目录

一,函数清单

1.socket 方法

2.bind 方法

3.listen 方法

4.accept 方法(阻塞函数)

5.recv 方法(阻塞函数)

6.send 方法

7.close 方法

8.htonl 方法

9.htons 方法

10.fcntl 方法

二,代码实现

1.阻塞型服务端

2.非阻塞型服务端


一,函数清单

1.socket 方法

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>

int socket(int domain, int type, int protocol);

功能

  • 创建用于通信的套接字,并返回一个指向该套接字的文件描述符。

参数

  1. domain:指定套接字的协议族。常见的值有AF_INET(IPv4)和AF_INET6(IPv6)。
  2. type:指定套接字的类型。常见的值有SOCK_STREAM(面向连接的可靠字节流)和SOCK_DGRAM(无连接的数据报文)。
  3. protocol:指定协议。通常使用0,表示默认选择。

返回值

  • 如果成功,则返回新套接字的文件描述符。如果出现错误,则返回-1,并设置errno。

2.bind 方法

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

功能

  • 将套接字与特定的IP地址和端口绑定。

参数

  1. sockfd:socket返回的套接字描述符。
  2. addr:指向要绑定的本地地址的结构体(通常是一个sockaddr_in或sockaddr_in6结构体)。
  3. addrlen:本地地址的长度(通常是sizeof(struct sockaddr_in)或sizeof(struct sockaddr_in6))。

返回值

  • 如果成功,则返回0。如果出现错误,则返回-1,并设置errno。

3.listen 方法

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>

int listen(int sockfd, int backlog);

功能

  • 开始监听指定套接字上的连接请求。

参数

  1. sockfd:socket返回的套接字描述符。
  2. backlog:等待连接队列的最大长度。如果连接请求到达时如果队列已满,则客户端可能会收到ECONNREFUSED指示的错误,如果底层协议支持重传,则请求可能已满忽略,以便稍后重试连接成功。

返回值

  • 如果成功,则返回0。如果出现错误,则返回-1,并设置errno。

4.accept 方法(阻塞函数)

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

功能

  • 接受一个连接请求,返回一个新的套接字描述符与客户端通信。

参数

  1. sockfd:socket返回的套接字描述符。
  2. addr:指向用于存放客户端地址的结构体的指针。通常指定为 struct  sockaddr_in 结构体。
  3. addrlen:用于传递addr结构体的长度。

返回值

  • 如果成功,这些系统调用将返回被接受套接字的文件描述符(一个非负整数)。如果出现错误,则返回-1,适设置errno,并且保持addrlen不变。

5.recv 方法(阻塞函数)

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

ssize_t recv(int sockfd, void *buf, size_t len, int flags);

功能

  • 从已连接的套接字接收数据。

参数

  1. sockfd:accept返回的套接字描述符。
  2. buf:接收数据的缓冲区。
  3. len:缓冲区的长度。
  4. flags:接收操作的标志,一般设置为0。

返回值

  • 返回接收到的字节数,如果发生错误则返回-1。如果发生错误,则设置errno来指示错误。当客户端连接关闭时,返回值将为0。

6.send 方法

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

ssize_t send(int sockfd, const void *buf, size_t len, int flags);

功能

  • 向已连接的套接字发送数据。

参数

  1. sockfd:accept返回的套接字描述符。
  2. buf:包含要发送数据的缓冲区。
  3. len:要发送的数据长度。
  4. flags:发送操作的标志,一般设置为0。

返回值

  • 如果成功,这些调用将返回发送的字节数。如果出现错误,则返回-1,并设置errno。

7.close 方法

#include <unistd.h>

int close(int fd);

功能

  • 关闭文件描述符

参数

  1. fd:要关闭的文件描述符。

返回值

  • 成功返回零。如果出现错误,则返回-1,并设置errno。

8.htonl 方法

#include <arpa/inet.h>

uint32_t htonl(uint32_t hostlong);

功能

  • 将无符号整数hostlong从主机字节顺序转换为网络字节顺序。

9.htons 方法

#include <arpa/inet.h>

uint16_t htons(uint16_t hostshort);

功能

  • 将无符号短整数hostshort从主机字节顺序转换为网络字节顺序。

10.fcntl 方法

#include <unistd.h>
#include <fcntl.h>

int fcntl(int fd, int cmd, ... /* arg */ );

功能

  • 操作文件描述符的特性,可设置成非阻塞IO。

参数

  1. fd:要设置的文件描述符。
  2. cmd:对fd要执行操作的命令,比如F_GETFL,F_SETFL。

返回值

  • 对于成功的调用,返回值取决于操作命令,如果出现错误,则返回-1,并适当地设置errno。

二,代码实现

1.阻塞型服务端

代码

  • accept和recv都是阻塞型的函数,在accept上是阻塞客户端的连接,在recv上是阻塞读取已连接客户端的数据。
  • 为实现连续和客户端进行通信,必须将recv放在一个master循环里,用于一直读取客户端发来的数据。
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>

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


#define BUFFER_LENGTH   1024

//初始化服务端,返回其文件描述符
int init_server(int port){
    //返回服务端fd,通常为3,前面0,1,2用于表示标准输入,输出,错误值
    int sfd = socket(AF_INET,SOCK_STREAM,0);

    if(-1 == sfd){
        printf("socket error code: %d codeInfo: %s\n",errno,strerror(errno));
        return -1;
    }

    struct sockaddr_in servAddr;
    memset(&servAddr,0,sizeof(struct sockaddr_in));
    servAddr.sin_family = AF_INET;  //ipv4
    servAddr.sin_addr.s_addr = htonl(INADDR_ANY);   //0.0.0.0
    servAddr.sin_port = htons(port);    //端口号
    
    //绑定IP和端口号
    if(-1 == bind(sfd,(struct sockaddr*)&servAddr,sizeof(struct sockaddr_in)))
    {
        printf("bind error code: %d codeInfo: %s\n",errno,strerror(errno));
        return -1;
    }

    //监听该套接字上的连接
    if(-1 == listen(sfd,10))
    {
        printf("listen error code: %d codeInfo: %s\n",errno,strerror(errno));
        return -1;
    }

    return sfd;
}

int main(int argc,char *argv[]){

    if(argc < 2)return -1;

    int port = atoi(argv[1]);   //atoi:将字符串转换为整数
    int sfd = init_server(port);
    printf("server fd: %d\n",sfd);

    struct sockaddr_in clientAddr;
    socklen_t len = sizeof(struct sockaddr_in);
    int cfd = accept(sfd,(struct sockaddr*)&clientAddr,&len);   //阻塞函数
    printf("client fd: %d\n",cfd);
    while (1)
    {//master循环:因为recv是阻塞函数,为实现连续性收发,必须放在while循环里
        char data[BUFFER_LENGTH]={0};
        int recvLen = recv(cfd,data,BUFFER_LENGTH,0);       //阻塞在cfd里是否有数据可读
        if(recvLen < 0){
            printf("recv client fd %d errno: %d\n",cfd,errno);
        }else if(recvLen == 0){
            printf("client fd %d close\n",cfd);
            break;
        }else{
            printf("recv client fd %d data: %s\n",cfd,data);
            send(cfd,data,recvLen,0);
        }
    }
    
    return 0;
}

运行

  • 测试工具:NetAssist 模拟客户端工具,测试服务端代码。

2.非阻塞型服务端

代码

  • 在accept的相应代码前添加如下代码,但不要直接在上述代码中添加,不然可能未及时等到客户端连接,使accept返回-1。
int flags = fcntl(sfd,F_GETFL,0);    //sfd为服务端文件描述符
flags |= O_NONBLOCK;
fcntl(sfd,F_SETFL,flags);
  • 以下是用于测试上面这一段代码是否将服务端设置成非阻塞型。
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>

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


#define BUFFER_LENGTH   1024

//初始化服务端,返回其文件描述符
int init_server(int port){
    //返回服务端fd,通常为3,前面0,1,2用于表示标准输入,输出,错误值
    int sfd = socket(AF_INET,SOCK_STREAM,0);

    if(-1 == sfd){
        printf("socket error code: %d codeInfo: %s\n",errno,strerror(errno));
        return -1;
    }

    struct sockaddr_in servAddr;
    memset(&servAddr,0,sizeof(struct sockaddr_in));
    servAddr.sin_family = AF_INET;  //ipv4
    servAddr.sin_addr.s_addr = htonl(INADDR_ANY);   //0.0.0.0
    servAddr.sin_port = htons(port);    //端口号
    
    //绑定IP和端口号
    if(-1 == bind(sfd,(struct sockaddr*)&servAddr,sizeof(struct sockaddr_in)))
    {
        printf("bind error code: %d codeInfo: %s\n",errno,strerror(errno));
        return -1;
    }

    //监听该套接字上的连接
    if(-1 == listen(sfd,10))
    {
        printf("listen error code: %d codeInfo: %s\n",errno,strerror(errno));
        return -1;
    }

    return sfd;
}

int main(int argc,char *argv[]){

    if(argc < 2)return -1;

    int port = atoi(argv[1]);   //atoi:将字符串转换为整数
    int sfd = init_server(port);
    printf("server fd: %d\n",sfd);

    struct sockaddr_in clientAddr;
    socklen_t len = sizeof(struct sockaddr_in);
    int cfd = accept(sfd,(struct sockaddr*)&clientAddr,&len);   //阻塞函数
    printf("client fd: %d\n",cfd);
    
    return 0;
}

运行

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/729710.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

0126 线性表

目录 2.线性表 2.1线性表的定义和基本概念 2.1部分习题 2.2线性表的顺序表示 2.2部分习题 2.3线性表的链式表示 2.3部分习题 2.线性表 2.1线性表的定义和基本概念 2.1部分习题 1.线性表是具有n个&#xff08;&#xff09;的有限序列 A.数据表 B.字符 C.…

FPGA纯verilog实现UDP协议栈,sgmii接口SFP光口收发,提供工程源码和技术支持

目录 1、前言2、我这里已有的UDP方案3、该UDP协议栈性能4、详细设计方案SFPGMII AXIS接口模块AXIS FIFOUDP协议栈1G/2.5G Ethernet PCS/PMA or SGMII 5、vivado工程1-->B50610 工程6、上板调试验证并演示准备工作查看ARPUDP数据回环测试 7、福利&#xff1a;工程代码的获取 …

c++日程管理系统

一.需求分析 多功能日历&#xff08;要求有简单ui&#xff09; 要求&#xff1a; 1.使用c代码用visual stdio运行 2.用户登录注册 3.登录后给用户三大功能选择&#xff1a; &#xff08;1&#xff09;基本日历&#xff1a;显示日历,默认六月&#xff0c;每日有对应的日程 &…

开源防病毒引擎ClamAV

本文软件是应网友 Windows 的要求折腾的&#xff1b; 什么是 ClamAV &#xff1f; ClamAV 是一个开源 ( GPLv2 ) 反病毒工具包&#xff0c;专为邮件网关上的电子邮件扫描而设计。它提供了许多实用程序&#xff0c;包括灵活且可扩展的多线程守护程序、命令行扫描程序和用于自动数…

尚硅谷Docker实战教程-笔记09【高级篇,DockerFile解析】

尚硅谷大数据技术-教程-学习路线-笔记汇总表【课程资料下载】视频地址&#xff1a;尚硅谷Docker实战教程&#xff08;docker教程天花板&#xff09;_哔哩哔哩_bilibili 尚硅谷Docker实战教程-笔记01【基础篇&#xff0c;Docker理念简介、官网介绍、平台入门图解、平台架构图解】…

LSTM介绍

LSTM ft表示 遗忘门。LSTM对于每一次的输入,首先决定遗忘掉之前的哪些记忆。将ft和t-1时刻的细胞状态相乘,得出将遗忘哪些记忆。 记忆门 是用来控制是否将t时刻的数据并入细胞状态。tanh函数可以将此刻向量中的有效信息提取出来,为gt。sigmoid函数用于控制此刻多少记忆进入…

阿里云ACE认证和华为云HCIE认证对比分析

最近有不少小伙伴私信问我&#xff0c;阿里云、腾讯云、华为云这几大厂商的云认证&#xff0c;哪一个更好&#xff0c;今天有空来跟大家认真地分析一下。 01-从云计算市场占有率来看 作为国内云计算市场的探路人&#xff0c;阿里虽然一路走来有过很多坎坷&#xff0c;但也不负…

Linux系统优化策略

Linux系统优化策略 1.禁用不需要的服务 在Linux系统中禁用不需要的服务可以通过以下步骤进行&#xff1a; 使用以下命令查看当前正在运行的服务&#xff1a; systemctl list-unit-files --typeservice根据需要禁用特定的服务&#xff0c;使用以下命令&#xff1a; systemctl …

【LeetCode周赛】2022上半年题目精选集——双指针

文章目录 2271. 毯子覆盖的最多白色砖块数思路代码 2302. 统计得分小于 K 的子数组数目代码1——前缀和滑动窗口代码2——双指针 O ( 1 ) O(1) O(1)空间 &#xff08;代码1的优化&#xff09; https://leetcode.cn/circle/discuss/G0n5iY/ 2271. 毯子覆盖的最多白色砖块数 22…

Win10安全中心怎么关闭?Win10安全中心关闭方法

Win10安全中心怎么关闭&#xff1f;关闭Win10的安全中心可以帮助用户自定义系统的安全和防护设置&#xff0c;但有些用户不知道怎么操作才能关闭安全中心&#xff0c;首先用户需要打开Win10电脑的设置选项&#xff0c;接着打开安全中心&#xff0c;然后关掉安全中心的实时保护、…

STM32CubeMX使用示例---生成LED闪烁工程

这里记录一下通过STM32CubeMX配置STM32G030C8T6&#xff0c;生成LED闪烁的示例工程的过程&#xff0c;用来学习使用STM32CubeMX&#xff1b; 以STM32G030C8T6 PB4 脚做LED 输出闪烁为例&#xff0c;外部8MHZ 晶振,系统主频64MHZ,LED 灯1 秒钟闪烁一次做一个示例程序。 文章目录…

Go语言程序设计(八)数据输入输出

Go语言提供了多种用于实现数据输入、输出的函数,这些函数在fmt包中实现。在输入、输出数据时,首先要导入fmt包,导入语句为: import "fmt" 一、标准输出函数 数据输出(Data Output),是计算机对各类输入数据进行加工处理后,将结果以用户所要求的形式输出到标准输出设…

OpenCV使用`clone()`函数来进行深度拷贝,拷贝后的`image_clone`修改不会影响原始图像`image`

这是完整的代码: #include <opencv2/opencv.hpp>int main() {// 创建一个白色的图像cv::Mat image(500, 500, CV_8UC3, cv

SpringCloud微服务(三)RabbitMQ、SpringAMQP、elasticsearch、DSL、MQ、ES详细介绍

目录 一、初始MQ 同步调用 异步调用 什么是MQ 执行下面的命令来运行MQ容器&#xff1a; 如果冲突了&#xff0c;可以先查询 RabbitMQ概述 常见消息模型 HelloWorld案例 二、SpringAMQP 引入依赖 Work Queue 消费预取限制 ​编辑 发布、订阅 发布订阅Fanout Ex…

作物计数方法之合并信息生成json标签的方法

在研究农情的方向中&#xff0c;作物计数是一个很重要的方向&#xff0c;前文已经提到了一些要使用的方法 前文链接&#xff1a;作物计数方法汇总_追忆苔上雪的博客-CSDN博客 在研究计数过程中&#xff0c;还需要将上文处理过的数据信息存入json文件方便后续使用&#xff0c;这…

Array.from详解

德玛玩前端 2023-07-07 在以往的开发中&#xff0c;对于Array.from的了解是from是Array的静态方法&#xff0c;可以将类数组和迭代对象转换为数组&#xff0c;可以结合Set集合快速实现数组的去重&#xff0c;一直以为Array,from()只有一个参数&#xff0c;不是传类数组就是可迭…

idea打包项目时报错 There are test failures

出现这个错误时要点击跳过测试类的按钮&#xff0c;图中的这个圆圈&#xff0c;可以看到test已经被划掉了 再点击package打包&#xff0c;成功。

启航RK3588边缘计算之旅:保定飞凌OK3588开发板

启航RK3588边缘计算之旅&#xff1a;保定飞凌OK3588开发板 引言&#xff1a; 随着人工智能技术的飞速发展&#xff0c;人们对于能够提供高性能和灵活性的智能设备有着极大的需求。作为人工智能领域的先锋企业&#xff0c;保定飞凌公司在设计和生产高性能处理器方面取得了卓越的…

在服务器从零开始配置conda、pytorch、cv2

疯掉了 希望是最后一次 0.配置WinSCP和PUTTY 在Windows上使用PuTTY进行SSH连接-腾讯云开发者社区-腾讯云 1.配置conda 如何在Linux服务器上安装Anaconda&#xff08;超详细&#xff09;_linux安装anaconda_流年若逝的博客-CSDN博客 实验室远程登录Linux服务器并配置环境_远…

Linux性能优化实践——平均负载

平均负载&#xff08;Load Average&#xff09; 当我们输入uptime命令时&#xff0c; 这里有几个参数&#xff0c;解释如下 0:54 &#xff1a;当前时间&#xff1b;up 50 mins&#xff1a;系统运行时间&#xff1b;2 users&#xff1a;正在登录用户数&#xff1b;load avera…