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

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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zhk___

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值