一种基于Linux的网络聊天室

网络聊天室是一种基于网络的实时通讯工具,它能够让用户在不同的地方通过网络进行交流。

程序原理

网络聊天室程序主要包含以下几个部分:

服务器端:用于接收和转发客户端发送的消息。

客户端:用于与服务器进行连接,并发送和接收消息。

当客户端连接服务器时,服务器会为每个客户端分配一个唯一的套接字描述符,用于标识该客户端。客户端可以通过套接字描述符向服务器发送消息,服务器收到消息后会将其转发给其他客户端。

服务器端实现

服务器端的实现主要包括以下几个步骤:

创建套接字:使用 socket 函数创建一个套接字,用于监听客户端连接请求。

绑定端口:使用 bind 函数将套接字与指定的端口号绑定,以便客户端能够连接服务器。

监听连接请求:使用 listen 函数监听客户端连接请求。

接受连接请求:使用 accept 函数接受客户端连接请求,并为该客户端分配一个唯一的套接字描述符。

接收和转发消息:使用 recv 函数接收客户端发送的消息,并使用 send 函数将消息转发给其他客户端。

下面是服务器端的代码示例:

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

#define MAX_CLIENTS 10
#define BUF_SIZE 1024

int main(int argc, char *argv[]) 
{
    int server_fd, client_fd[MAX_CLIENTS], max_fd, i, activity, valread;
    struct sockaddr_in server_addr, client_addr;
    char buffer[BUF_SIZE] = {0};
    fd_set read_fds;

    // 创建套接字
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) 
    {
        perror("socket failed");
        exit(EXIT_FAILURE);
    }

    // 设置服务器地址
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = INADDR_ANY;
    server_addr.sin_port = htons(atoi(argv[1]));

    // 绑定端口
    if (bind(server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) 
    {
        perror("bind failed");
        exit(EXIT_FAILURE);
    }

    // 监听连接请求
    if (listen(server_fd, MAX_CLIENTS) < 0) 
    {
        perror("listen failed");
        exit(EXIT_FAILURE);
    }

    // 初始化客户端套接字描述符数组
    for (i = 0; i < MAX_CLIENTS; i++) 
    {
        client_fd[i] = 0;
    }

    while (1) 
    {
        // 清空文件描述符集合
        FD_ZERO(&read_fds);

        // 将服务器套接字加入文件描述符集合
        FD_SET(server_fd, &read_fds);
        max_fd = server_fd;

        // 将所有客户端套接字加入文件描述符集合
        for (i = 0; i < MAX_CLIENTS; i++) 
        {
            if (client_fd[i] > 0) 
            {
                FD_SET(client_fd[i], &read_fds);
            }

            if (client_fd[i] > max_fd) 
            {
                max_fd = client_fd[i];
            }
        }

        // 等待活动的套接字
        activity = select(max_fd + 1, &read_fds, NULL, NULL, NULL);

        if (activity < 0) 
        {
            perror("select failed");
            exit(EXIT_FAILURE);
        }

        // 如果有新的连接请求,接受连接,并将其加入客户端套接字描述符数组
        if (FD_ISSET(server_fd, &read_fds)) 
        {
            int addr_len = sizeof(client_addr);
            if ((client_fd[i] = accept(server_fd, (struct sockaddr *)&client_addr, (socklen_t *)&addr_len)) < 0) 
            {
                perror("accept failed");
                exit(EXIT_FAILURE);
            }

            // 发送欢迎消息给新连接的客户端
            char *welcome_msg = "Welcome to the chat room!";
            send(client_fd[i], welcome_msg, strlen(welcome_msg), 0);
        }

        // 接收和转发消息
        for (i = 0; i < MAX_CLIENTS; i++) 
        {
            if (FD_ISSET(client_fd[i], &read_fds)) 
            {
                valread = recv(client_fd[i], buffer, BUF_SIZE, 0);
                if (valread <= 0) 
                {
                    // 如果客户端关闭连接,从客户端套接字描述符数组中移除该套接字
                    close(client_fd[i]);
                    client_fd[i] = 0;
                } 
                else 
                {
                    // 将客户端发送的消息转发给其他客户端
                    for (int j = 0; j < MAX_CLIENTS; j++) 
                    {
                        if (j != i && client_fd[j] > 0) 
                        {
                            send(client_fd[j], buffer, strlen(buffer), 0);
                        }
                    }
                }
            }
        }
    }

    return 0;
}

客户端实现

客户端的实现主要包括以下几个步骤:

创建套接字:使用 socket 函数创建一个套接字。

连接服务器:使用 connect 函数连接服务器。

发送和接收消息:使用 send 函数向服务器发送消息,使用 recv 函数接收服务器转发的消息。

下面是客户端的代码示例:

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

#define BUF_SIZE 1024

int main(int argc, char *argv[]) 
{
    int client_fd;
    struct sockaddr_in server_addr;
    char buffer[BUF_SIZE] = {0};

    // 创建套接字
    if ((client_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) 
    {
        perror("socket failed");
        exit(EXIT_FAILURE);
    }

    // 设置服务器地址
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(atoi(argv[2]));

    // 将IP地址从点分十进制转换为二进制格式
    if (inet_pton(AF_INET, argv[1], &server_addr.sin_addr) <= 0) 
    {
        perror("inet_pton failed");
        exit(EXIT_FAILURE);
    }

    // 连接服务器
    if (connect(client_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) 
    {
        perror("connect failed");
        exit(EXIT_FAILURE);
    }

    // 接收欢迎消息
    if (recv(client_fd, buffer, BUF_SIZE, 0) > 0) 
    {
        printf("%s", buffer);
    }

    // 发送和接收消息
    while (1) 
    {
        fgets(buffer, BUF_SIZE, stdin);
        send(client_fd, buffer, strlen(buffer), 0);
        memset(buffer, 0, BUF_SIZE);
        recv(client_fd, buffer, BUF_SIZE, 0);
        printf("%s", buffer);
    }

    return 0;
}

编译和运行

将服务器端和客户端的代码保存到两个不同的文件中,并使用以下命令编译:

gcc server.c -o server
gcc client.c -o client

然后在一个终端中运行服务器:

./server 8080

其中 8080 是服务器监听的端口号。

在另一个终端中运行客户端:

./client 127.0.0.1 8080

其中 127.0.0.1 是服务器的IP地址,8080 是服务器的端口号。

运行客户端后,将能够在终端中输入消息,并将其发送给服务器。服务器将把该消息转发给其他连接的客户端。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值