Linux下,基于TCP与UDP协议,不同进程下单线程通信服务器

news/2024/5/18 12:07:53 标签: 服务器, linux, tcp/ip, udp, c语言, c++

C语言实现Linux下,基于TCP与UDP协议,不同进程下单线程通信服务器

一、TCP单线程通信服务器

  • 先运行server端,再运行client端
  • 输入"exit" 是退出

1.1 server_TCP.c

**#include <my_head.h>

#define PORT 6666
#define IP "192.168.125.103"

int main(int argc, const char *argv[])
{
    //  创建流式套接字
    int server_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (server_fd < 0)
    {
        ERR_MSG("socket");
        return -1;
    }
    printf("套接字创建成功 server_fd = %d\n", server_fd);

    //  允许端口快速复用
    int reuse = 1;
    if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0)
    {
        ERR_MSG("setsockopt");
        return -1;
    }
    printf("允许端口快速复用成功\n");

    //  绑定服务器的地址信息    必须绑定
    struct sockaddr_in server_in;              //  用于绑定本主机的信息
    server_in.sin_family = AF_INET;            //  必须填 AF_INET
                                               //  因为前面创建流式套接字用的是 IPv4
    server_in.sin_port = htons(PORT);          //  指定端口号
    server_in.sin_addr.s_addr = inet_addr(IP); //  绑定本机IP
    if (bind(server_fd, (struct sockaddr *)&server_in, sizeof(server_in)) < 0)
    {
        ERR_MSG("bin");
        return -1;
    }
    printf("bind 成功\n");

    //  将套接字转换为被动监听状态
    if (listen(server_fd, 256) < 0)
    {
        ERR_MSG("listen");
        return -1;
    }
    printf("listen 成功\n");

    //  获取连接成功的客户端信息,生成一个新的文件描述符
    //  该文件描述符才是与客户端通信的文件描述符
    struct sockaddr_in client_in;                                             //  用于存放接收的客户端的信息
    socklen_t addrlen = sizeof(client_in);                                    //  用于存放客户端传来的信息的长度
    int new_fd = accept(server_fd, (struct sockaddr *)&client_in, &addrlen); //  连接客户端
    if (new_fd < 0)
    {
        ERR_MSG("accept");
        return -1;
    }
    printf("new_fd = %d    __%d__\n", new_fd, __LINE__);

    //  输出客户端IP和端口号
    printf("client IP = %s\n", inet_ntoa(client_in.sin_addr));
    printf("client port = %d\n", ntohs(client_in.sin_port));

    //  接收数据
    char buff[128];
    ssize_t res = 0;
    while (1)
    {
        //  清空暂存区
        bzero(buff, sizeof(buff));
        //  接收数据    当最后一个参数为 0 时,也可以用 read
        // res = recv(new_fd, buff, sizeof(buff), 0);
        res = read(new_fd, buff, sizeof(buff));
        if (res < 0)
        {
            ERR_MSG("recv");
            return -1;
        }
        //  写端关闭了,即客户端关闭
        else if (0 == res)
        {
            printf("[ %s : %d ]客户端断开链接\n", inet_ntoa(client_in.sin_addr),
                   ntohs(client_in.sin_port));
            break;
        }
        //  输出客户端信息 和 接收的数据
        printf("[ %s : %d ] [massage : %s ]\n", inet_ntoa(client_in.sin_addr),
               ntohs(client_in.sin_port), buff);

        //  接收的数据为 退出 (exit)
        if (!strcmp(buff, "exit"))
        {
            printf("已断开\n");
            break;
        }

        //  发送数据
        //  向客户端发送消息
        printf("回复:");
        scanf("%s", buff);
        if (!strcmp(buff, "exit"))
        {
            printf("已断开\n");
            break;
        }
        //  发送
        if (send(new_fd, buff, sizeof(buff), 0) < 0)
        {
            ERR_MSG("send");
            return -1;
        }
        printf("buff = %s\n", buff);
        putchar(10);
    }

    //  关闭套接字
    close(server_fd);
    close(new_fd);
    return 0;
}

1.2 client_TCP.c

#include <my_head.h>

#define SERVER_PORT 6666            //  服务器端口号
#define SERVER_IP "192.168.125.103" //  服务器IP

int main(int argc, const char *argv[])
{
    //  创建客户端流式套接字
    int client_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (client_fd < 0)
    {
        ERR_MSG("socket");
        return -1;
    }
    printf("套接字创建成功 client_fd = %d\n", client_fd);

    //  端口快速复用
    int reuse = 1;
    if (setsockopt(client_fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0)
    {
        ERR_MSG("setsockopt");
        return -1;
    }
    printf("允许端口快速复用成功\n");

    //  绑定客户端信息,非必须绑定,建议不绑
    //  如果不绑定,操作系统会自动分配端口号

    //  连接服务器
    struct sockaddr_in server_in;
    server_in.sin_addr.s_addr = inet_addr(SERVER_IP);
    server_in.sin_port = htons(SERVER_PORT);
    server_in.sin_family = AF_INET;
    //  连接
    if (connect(client_fd, (struct sockaddr *)&server_in, sizeof(server_in)) < 0)
    {
        ERR_MSG("connect");
        return -1;
    }

    char buff[128];
    ssize_t res = 0;
    while (1)
    {
        //  发送消息
        printf("请输入 : ");
        fgets(buff, sizeof(buff), stdin);
        buff[strlen(buff) - 1] = 0;
        if (send(client_fd, buff, sizeof(buff), 0) < 0)
        {
            ERR_MSG("send");
            return -1;
        }
        if (!strcmp(buff, "exit"))
        {
            printf("断开链接\n");
            break;
        }

        printf("发送成功\n");

        bzero(buff, sizeof(buff));

        //  接收消息
        res = recv(client_fd, buff, sizeof(buff), 0);
        if (res < 0)
        {
            ERR_MSG("recv");
            return -1;
        }
        else if (0 == res)
        {
            printf("[ %s : %d ] 服务器断开链接   __%d__\n", SERVER_IP, SERVER_PORT, __LINE__);
            break;
        }
        printf("[ %s : %d ] [massage : %s ]\n", SERVER_IP, SERVER_PORT, buff);
    }

    close(client_fd);
    return 0;
}

二、TCP单线程通信服务器

  • 先运行server端,再运行client端
  • 输入"exit" 是退出

2.1 server_UDP.c

#include <my_head.h>

#define SERVER_PORT 6666
#define SERVER_IP "192.168.125.103"

int main(int argc, const char *argv[])
{
    //  创建报式套接字
    int client_fd = socket(AF_INET, SOCK_DGRAM, 0);
    if (client_fd < 0)
    {
        ERR_MSG("socket");
        return -1;
    }
    printf("套接字创建成功 client_fd = %d\n", client_fd);

    //  允许端口快速复用
    int reuse = 1;
    if (setsockopt(client_fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0)
    {
        ERR_MSG("setsockopt");
        return -1;
    }
    printf("允许端口快速复用成功\n");

    //  绑定客户端信息,非必须绑定,建议不绑
    //  如果不绑定,操作系统会自动分配端口号

    //  指定服务器的信息
    struct sockaddr_in server_addr;                     //  用于绑定本主机的信息
    server_addr.sin_family = AF_INET;                   //  必须填 AF_INET
                                                        //  因为前面创建报式套接字用的是 IPv4
    server_addr.sin_port = htons(SERVER_PORT);          //  指定端口号
    server_addr.sin_addr.s_addr = inet_addr(SERVER_IP); //  绑定本机IP

    //  发送数据
    char buff[128];
    ssize_t res = 0;
    struct sockaddr_in client_addr;
    socklen_t client_len = sizeof(client_addr);
    while (1)
    {
        //  清空暂存区
        bzero(buff, sizeof(buff));
        //  发送数据
        //  向客户端发送消息
        printf("请输入 : ");
        scanf("%s", buff);
        
        //  发送
        if (sendto(client_fd, buff, sizeof(buff), 0, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
        {
            ERR_MSG("sendto");
            return -1;
        }
        if (!strcmp(buff, "exit"))
        {
            printf("已断开\n");
            break;
        }
        printf("buff = %s\n", buff);

        //  接收数据    当最后一个参数为 0 时,也可以用 read
        // res = recv(client_fd, buff, sizeof(buff), 0);
        // res = read(client_fd, buff, sizeof(buff));
        res = recvfrom(client_fd, buff, sizeof(buff), 0, (struct sockaddr *)&client_addr, &client_len);
        if (res < 0)
        {
            ERR_MSG("recv");
            return -1;
        }

        //  输出客户端信息 和 接收的数据
        printf("[ %s : %d ] [massage : %s ]\n", inet_ntoa(client_addr.sin_addr),
               htons(client_addr.sin_port), buff);

        //  接收的数据为 退出 (exit)
        if (!strcmp(buff, "exit"))
        {
            printf("已断开\n");
            break;
        }

        putchar(10);
    }

    //  关闭套接字
    close(client_fd);
    return 0;
}

2.2 client_UDP.c

#include <my_head.h>

#define PORT 6666
#define IP "192.168.125.103"

int main(int argc, const char *argv[])
{
    //  创建报式套接字
    int server_fd = socket(AF_INET, SOCK_DGRAM, 0);
    if (server_fd < 0)
    {
        ERR_MSG("socket");
        return -1;
    }
    printf("套接字创建成功 server_fd = %d\n", server_fd);

    //  允许端口快速复用
    int reuse = 1;
    if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0)
    {
        ERR_MSG("setsockopt");
        return -1;
    }
    printf("允许端口快速复用成功\n");

    //  绑定服务器的地址信息    必须绑定
    struct sockaddr_in server_in;              //  用于绑定本主机的信息
    server_in.sin_family = AF_INET;            //  必须填 AF_INET
                                               //  因为前面创建报式套接字用的是 IPv4
    server_in.sin_port = htons(PORT);          //  指定端口号
    server_in.sin_addr.s_addr = inet_addr(IP); //  绑定本机IP
    //  绑定
    if (bind(server_fd, (struct sockaddr *)&server_in, sizeof(server_in)) < 0)
    {
        ERR_MSG("bind");
        return -1;
    }
    printf("bind 成功\n");

    //  UDP不用连接,所以也不用监听

    //  接收数据
    char buff[128];
    ssize_t res = 0;
    struct sockaddr_in client_addr;
    socklen_t client_len = sizeof(client_addr);
    while (1)
    {
        //  清空暂存区
        bzero(buff, sizeof(buff));
        //  接收数据    当最后一个参数为 0 时,也可以用 read
        // res = recv(new_fd, buff, sizeof(buff), 0);
        // res = read(server_fd, buff, sizeof(buff));
        res = recvfrom(server_fd, buff, sizeof(buff), 0, (struct sockaddr *)&client_addr, &client_len);
        if (res < 0)
        {
            ERR_MSG("recvfrom");
            return -1;
        }

        //  输出客户端信息 和 接收的数据
        printf("[ %s : %d ] [massage : %s ]\n", inet_ntoa(client_addr.sin_addr),
               htons(client_addr.sin_port), buff);

        //  接收的数据为 退出 (exit)
        if (!strcmp(buff, "exit"))
        {
            printf("已断开\n");
            break;
        }

        //  发送数据
        //  向客户端发送消息
        printf("回复:");
        scanf("%s", buff);
        if (!strcmp(buff, "exit"))
        {
            printf("已断开\n");
            break;
        }
        //  发送
        if (sendto(server_fd, buff, sizeof(buff), 0, (struct sockaddr *)&client_addr, client_len) < 0)
        {
            ERR_MSG("sendto");
            return -1;
        }
        printf("buff = %s\n", buff);
        putchar(10);
    }

    //  关闭套接字
    close(server_fd);
    return 0;
}

http://www.niftyadmin.cn/n/5036327.html

相关文章

JVM G1垃圾回收器学习笔记

前言 最近在工作中遇到频繁FullGC且YoungGC时间有时特别长的情况&#xff0c;而自己对JVM的垃圾回收也是一知半解&#xff0c;因此需要对JVM做系统的了解&#xff0c;为快速解决工作中的问题&#xff0c;能有效分析GC日志和业务代码&#xff0c;先从G1垃圾回收器开始学习&…

layUI.open在手机端小屏幕不能显示全页面,也没办法滑动

首先我的项目是点击编辑&#xff0c;打开一个编辑信息页面&#xff0c;在网页端显示效果如下&#xff1a; 有时候工作人员离开电脑&#xff0c;需要手机操作修改&#xff0c;但是弹出的编辑页面显示不全内容&#xff0c;也没办法通过触摸滑动页面看见左面的内容&#xff0c;如下…

网络编程 day2

TCPser TCPcli UDPser UDPcli

《Kubernetes部署篇:Ubuntu20.04基于外部etcd+部署kubernetes1.25.14集群(多主多从)》

一、部署架构图 1、架构图如下所示: 2、部署流程图如下所示: 二、环境信息 1、资源下载基于外部etcd+部署容器版kubernetes1.25.14集群资源合集 2、部署规划主机名K8S版本系统版本内核版本IP地址备注k8s-master-121.25.14Ubuntu 20.04.5 LTS5.15.0-69-generic192.168.1.12ma…

视频相关 压缩 编码 存储 查询 知识点

视频相关 压缩 编码 存储 查询 知识点 视频压缩&#xff1a;I帧、P帧、B帧 H264是新一代的编码标准&#xff0c;以高压缩高质量和支持多种网络的流媒体传输著称&#xff0c;在编码方面&#xff0c;我理解的他的理论依据是&#xff1a;参照一段时间内图像的统计结果表明&#…

PostgreSQL 16数据库的yum、编译、docker三种方式安装——筑梦之路

一、 docker方式 docker pull postgres:16.0docker rm -f lhrpg16docker run --name lhrpg16 -h lhrpg16 -d -p 54329:5432 -e POSTGRES_PASSWORDlhr -e TZAsia/Shanghai postgres:16.0docker exec -it lhrpg16 bashdocker exec -it lhrpg16 psql -U postgres -d postgressele…

基于java SpringBoot和HTML实验室预约管理系统设计

摘要 实验室信息管理系统是利用计算机网络技术、数据存储技术、快速数据处理技术对实验室进行全方位管理的计算机软件系统。实验室信息管理系统从最初仅完成数据存储和有限的网络功能&#xff0c;发展到现在可以处理海量数据&#xff0c;具备完善的管理职能&#xff0c;并且能够…

QMutableListIterator详解

目录 是什么&#xff1a; 1. 从列表中删除特定元素 2. 替换特定元素 是什么&#xff1a; Qt中&#xff0c;QMutableListIterator 是一个用于迭代和修改 QList&#xff08;动态数组&#xff09; 的类。QMutableListIterator 继承自 QListIterator&#xff0c;并添加了修改和删…