Ubuntu与本地用户交流是两种小方法

一、talk命令与本地用户交流

Linux的talk命令是一个视觉通信程序,它将你终端的行复制到另一个用户的终端,就像即时通讯服务一样。Talk命令在Unix-like操作系统中提供了一个文本聊天界面,让你可以实时与其他已登录的用户进行交流。

1.1下载talk及其服务

在Unbuntu20.04LTS中,在终端键入如下命令sudo apt-get install talk以及sudo apt-get install talk-server来下载talk及其服务。

1.2使用talk命令

talk命令的基本语法为talk person [ ttyname]。其中,person可以是你机器上的某个人的登录名,或者是另一台主机上的用户的形式'user@host'。ttyname参数可以指示适当的终端名称,其中ttyname的形式为'ttyXX'或'pts/X'。例如talk user [pts/13]

若不知道本地用户有哪些以及pts是多少,可以通过who命令进行查询。
实际操作如图

二、自己使用c语言编译代码以实现类似talk功能的程序

思考:这个程序应该支持本地用户之间的实时交流,因此需要一个服务器端来管理连接和转发消息,以及一个客户端来发送和接收消息。因此需要使用两个终端,一个充当服务器,一个充当客户端。

  1. 服务器端代码 (talk_server.c)
cpp 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <pthread.h>

#define PORT 9999
#define MAX_CLIENTS 10
#define BUFFER_SIZE 1024

int client_sockets[MAX_CLIENTS];
int client_count = 0;

// 处理客户端消息的函数
void *handle_client(void *arg) {
    int client_socket = *((int *)arg);
    char buffer[BUFFER_SIZE];

    while (1) {
        int bytes_received = recv(client_socket, buffer, BUFFER_SIZE, 0);
        if (bytes_received <= 0) {
            break;
        }

        buffer[bytes_received] = '\0';
        printf("Received: %s", buffer);

        // 广播消息给所有其他客户端
        for (int i = 0; i < client_count; i++) {
            if (client_sockets[i] != client_socket) {
                send(client_sockets[i], buffer, strlen(buffer), 0);
            }
        }
    }

    // 移除断开的客户端
    for (int i = 0; i < client_count; i++) {
        if (client_sockets[i] == client_socket) {
            for (int j = i; j < client_count - 1; j++) {
                client_sockets[j] = client_sockets[j + 1];
            }
            client_count--;
            break;
        }
    }

    close(client_socket);
    free(arg);
    return NULL;
}

int main() {
    int server_socket = socket(AF_INET, SOCK_STREAM, 0);
    if (server_socket == -1) {
        perror("Socket creation failed");
        exit(EXIT_FAILURE);
    }

    struct sockaddr_in server_addr;
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = INADDR_ANY;
    server_addr.sin_port = htons(PORT);

    if (bind(server_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {
        perror("Bind failed");
        close(server_socket);
        exit(EXIT_FAILURE);
    }

    if (listen(server_socket, MAX_CLIENTS) == -1) {
        perror("Listen failed");
        close(server_socket);
        exit(EXIT_FAILURE);
    }

    printf("Server started on port %d. Waiting for connections...\n", PORT);

    while (1) {
        struct sockaddr_in client_addr;
        socklen_t client_len = sizeof(client_addr);
        int client_socket = accept(server_socket, (struct sockaddr *)&client_addr, &client_len);

        if (client_socket == -1) {
            perror("Accept failed");
            continue;
        }

        printf("Accepted connection from %s:%d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));

        // 添加客户端到列表
        if (client_count < MAX_CLIENTS) {
            client_sockets[client_count++] = client_socket;

            // 创建线程处理客户端
            pthread_t thread;
            int *client_socket_ptr = malloc(sizeof(int));
            *client_socket_ptr = client_socket;
            pthread_create(&thread, NULL, handle_client, client_socket_ptr);
            pthread_detach(thread);
        } else {
            printf("Too many clients. Closing connection.\n");
            close(client_socket);
        }
    }

    close(server_socket);
    return 0;
}
  1. 客户端代码 (talk_client.c)
cpp 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <pthread.h>

#define PORT 9999
#define BUFFER_SIZE 1024

int client_socket;

// 接收消息的线程
void *receive_messages(void *arg) {
    char buffer[BUFFER_SIZE];
    while (1) {
        int bytes_received = recv(client_socket, buffer, BUFFER_SIZE, 0);
        if (bytes_received <= 0) {
            printf("Connection closed by server.\n");
            break;
        }
        buffer[bytes_received] = '\0';
        printf("\rReceived: %s\nYou: ", buffer);
        fflush(stdout);
    }
    return NULL;
}

// 发送消息的线程
void *send_messages(void *arg) {
    char buffer[BUFFER_SIZE];
    while (1) {
        printf("You: ");
        fflush(stdout);
        fgets(buffer, BUFFER_SIZE, stdin);

        // 去掉换行符
        buffer[strcspn(buffer, "\n")] = '\0';

        if (strcmp(buffer, "exit") == 0) {
            break;
        }

        send(client_socket, buffer, strlen(buffer), 0);
    }
    return NULL;
}

int main() {
    client_socket = socket(AF_INET, SOCK_STREAM, 0);
    if (client_socket == -1) {
        perror("Socket creation failed");
        exit(EXIT_FAILURE);
    }

    struct sockaddr_in server_addr;
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    server_addr.sin_port = htons(PORT);

    if (connect(client_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {
        perror("Connection failed");
        close(client_socket);
        exit(EXIT_FAILURE);
    }

    printf("Connected to the server. Type 'exit' to quit.\n");

    pthread_t receive_thread, send_thread;
    pthread_create(&receive_thread, NULL, receive_messages, NULL);
    pthread_create(&send_thread, NULL, send_messages, NULL);

    pthread_join(receive_thread, NULL);
    pthread_join(send_thread, NULL);

    close(client_socket);
    return 0;
}
  1. 编译和运行
    编译服务器端:gcc talk_server.c -o talk_server -lpthread
    编译客户端:gcc talk_client.c -o talk_client -lpthread
    启动服务器:./talk_server
    在新终端中启动客户端:./talk_client
  2. 实际运行


  1. 声明
    ①该程序仅支持本地通信,不支持跨网络。
    ②服务器端可以同时处理多个客户端连接。
    ③客户端之间可以实时发送和接收消息。
    ④输入 exit 可以退出客户端。

三、参考资料

Linux talk命令教程:如何实时与其他用户进行交流(附实例详解和注意事项)

相关推荐
broad-sky1 天前
Ubuntu上查看USB相机连接的是哪个口,如何查看
linux·数码相机·ubuntu
秋深枫叶红1 天前
嵌入式第三十七篇——linux系统编程——线程控制
linux·学习·线程·系统编程
可爱又迷人的反派角色“yang”1 天前
ansible的概念及基本操作(一)
运维·ansible
shaohui9731 天前
ARMv7 linux中断路由以及处理
linux·gic·cpsr·armv7
三小尛1 天前
linux的开发工具vim
linux·运维·vim
陈陈爱java1 天前
Conda 常用命令行
linux·windows·conda
twdnote1 天前
dokcer 环境中集成LibreOffice
linux
ChristXlx1 天前
Linux安装redis(虚拟机适用)
linux·运维·redis
源文雨1 天前
PVE实现USB硬盘盒在备份前自动上电/结束后自动断电脚本
linux·运维·服务器·备份·perl·pve·usb硬盘盒
ascarl20101 天前
准确--CentOS 7 配置用户资源限制(nofile / nproc)
linux·运维·centos