一、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功能的程序
思考:这个程序应该支持本地用户之间的实时交流,因此需要一个服务器端来管理连接和转发消息,以及一个客户端来发送和接收消息。因此需要使用两个终端,一个充当服务器,一个充当客户端。
- 服务器端代码 (
talk_server.c
)
#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;
}
- 客户端代码 (
talk_client.c
)
#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;
}
- 编译和运行
编译服务器端:gcc talk_server.c -o talk_server -lpthread
编译客户端:gcc talk_client.c -o talk_client -lpthread
启动服务器:./talk_server
在新终端中启动客户端:./talk_client
- 实际运行
- 声明
①该程序仅支持本地通信,不支持跨网络。
②服务器端可以同时处理多个客户端连接。
③客户端之间可以实时发送和接收消息。
④输入 exit 可以退出客户端。