½ñÌìÕâƪÎÄÕ»ù±¾ÉÏÊôÓÚ֮ǰÉÏѧѧϰ c ÓïÑԵĻعËÁË£¬ÒªÊµÏÖÒ»¸ö¼òµ¥µÄÁÄÌ칦ÄÜ£¬Æäʵ»¹ÊÇÐèÒª»°·ÑһЩ´ú¼ÛµÄ£¬ÕâÀïÃ滹ÊÇÉæ¼°µ½±È½Ï¶àµÄ֪ʶµÄ¡£±ÈÈ磺
±¾ÎÄΪÁ˼ò»¯Æڼ䣬½ö½öʵÏÖÒ»¸öÖÐÐÄ»¯µÄÁÄÌ죬ÒòΪÕâ¸öÎÒÃDZȽÏÊìϤ£¬¶øÇÒÔÚѧУÀïѧϰ c ÓïÑÔʱ£¬¶à¶àÉÙÉÙÀÏʦÈÃ×öʵϰҲÊÇд¹ýµÄ¡£
ok£¬Ò»Èç¼ÌÍùµÄÏ°¹ß£¬ÎÒÃÇÀ´¿´¿´Õâ¸ö³ÌÐò½»»¥·½Ê½ÊÇÈçºÎµÄ¡£
ҪʵÏÖ A ºÍ B ÁÄÌ죬Ê×ÏÈ£¬ÎÒÃÇÐèÒªÓиö·þÎñ¶Ë£¬·þÎñ¶ËÌ×½Ó×Ö°ó¶¨ÔÚÒ»¸ö¶Ë¿ÚÉÏ£¬È»ºóµÈ´ý¿Í»§¶ËA ºÍ B À´Á¬½Ó£¬·þÎñ¶Ë½« A ºÍ B µÄ¿Í»§¶ËÌ×½Ó×ÖÒýÓôæÔÚ×Ô¼ºµÄÄÚ´æÖУ¬A ·¢Ë͸øµÄÏûÏ¢ÏȾ¹ý·þÎñÆ÷½ÓÊÕ£¬·þÎñÆ÷·¢ÏÖÕâ¸öÊÇ A ·¢Ë͸ø B µÄ£¬È»ºó¾Íת·¢¸øµ½ B£¬Í¬Àí£¬Ò²ÊÇÒ»Ö¡£
Õâ¾ÍÊÇÉÏÊöµÄ¹ý³Ì£¬ÄÇ£¬ÎÒÃÇÈçºÎʵÏÖÕâ¸ö³ÌÐòÄØ£¬ÏÖÀ´¿´·þÎñ¶ËµÄ´úÂëʵÏÖ£ºmulti_client_server.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define MAX_CLIENTS 10
#define BUFFER_SIZE 2048
#define NAME_LEN 32
static unsigned int cli_count = 0;
static int uid = 10;
// Client structure
typedef struct {
struct sockaddr_in address;
int sockfd;
int uid;
char name[NAME_LEN];
} client_t;
client_t *clients[MAX_CLIENTS];
pthread_mutex_t clients_mutex = PTHREAD_MUTEX_INITIALIZER;
void str_trim_lf(char* arr, int length) {
for (int i = 0; i < length; i++) { // trim \\n
if (arr[i] == '\\n') {
arr[i] = '\\0';
break;
}
}
}
int find_client_sockfd(char *recipient_name, Client *clients, int max_clients) {
for (int i = 0; i < max_clients; i++) {
if (clients[i].sockfd != 0 && strcmp(clients[i].name, recipient_name) == 0) {
return clients[i].sockfd;
}
}
return -1;
}
void print_client_addr(struct sockaddr_in addr) {
printf("%d.%d.%d.%d",
addr.sin_addr.s_addr & 0xff,
(addr.sin_addr.s_addr & 0xff00) >> 8,
(addr.sin_addr.s_addr & 0xff0000) >> 16,
(addr.sin_addr.s_addr & 0xff000000) >> 24);
}
// Add clients to array
void queue_add(client_t *cl) {
pthread_mutex_lock(&clients_mutex);
for (int i = 0; i < MAX_CLIENTS; ++i) {
if (!clients[i]) {
clients[i] = cl;
break;
}
}
pthread_mutex_unlock(&clients_mutex);
}
// Remove clients to array
void queue_remove(int uid) {
pthread_mutex_lock(&clients_mutex);
for (int i = 0; i < MAX_CLIENTS; ++i) {
if (clients[i]) {
if (clients[i]->uid == uid) {
clients[i] = NULL;
break;
}
}
}
pthread_mutex_unlock(&clients_mutex);
}
// Send message to all clients except the sender
void send_message(char *s, int uid) {
pthread_mutex_lock(&clients_mutex);
for (int i = 0; i < MAX_CLIENTS; ++i) {
if (clients[i]) {
if (clients[i]->uid != uid) {
if (write(clients[i]->sockfd, s, strlen(s)) < 0) {
perror("ERROR: write to descriptor failed");
break;
}
}
}
}
pthread_mutex_unlock(&clients_mutex);
}
// Handle all communication with the client
void *handle_client(void *arg) {
char buff_out[BUFFER_SIZE];
char name[NAME_LEN];
int leave_flag = 0;
cli_count++;
client_t *cli = (client_t *)arg;
// Name
if (recv(cli->sockfd, name, NAME_LEN, 0) <= 0 || strlen(name) < 2 || strlen(name) >= NAME_LEN-1) {
printf("Enter the name correctly\\n");
leave_flag = 1;
} else {
strcpy(cli->name, name);
sprintf(buff_out, "%s has joined\\n", cli->name);
printf("%s", buff_out);
send_message(buff_out, cli->uid);
}
bzero(buff_out, BUFFER_SIZE);
while (1) {
if (leave_flag) {
break;
}
int receive = recv(cli->sockfd, buff_out, BUFFER_SIZE, 0);
if (receive > 0) {
if (strlen(buff_out) > 0) {
send_message(buff_out, cli->uid);
str_trim_lf(buff_out, strlen(buff_out));
printf("%s -> %s\\n", buff_out, cli->name);
}
} else if (receive == 0 || strcmp(buff_out, "exit") == 0) {
sprintf(buff_out, "%s has left\\n", cli->name);
printf("%s", buff_out);
send_message(buff_out, cli->uid);
leave_flag = 1;
} else {
printf("ERROR: -1\\n");
leave_flag = 1;
}
bzero(buff_out, BUFFER_SIZE);
}
close(cli->sockfd);
queue_remove(cli->uid);
free(cli);
cli_count--;
pthread_detach(pthread_self());
return NULL;
}
int main(int argc, char **argv) {
if (argc != 2) {
printf("Usage: %s <port>\\n", argv[0]);
return EXIT_FAILURE;
}
int port = atoi(argv[1]);
int listenfd = 0, connfd = 0;
struct sockaddr_in serv_addr;
struct sockaddr_in cli_addr;
pthread_t tid;
// Socket settings
listenfd = socket(AF_INET, SOCK_STREAM, 0);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(port);
// Signals
signal(SIGPIPE, SIG_IGN);
if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int)) < 0) {
perror("ERROR: setsockopt failed");
return EXIT_FAILURE;
}
// Binding
if (bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {
perror("ERROR: Bind failed");
return EXIT_FAILURE;
}
// Listening
if (listen(listenfd, 10) < 0) {
perror("ERROR: Listen failed");
return EXIT_FAILURE;
}
printf("<[ SERVER STARTED ]>\\n");
// Accept clients
while (1) {
socklen_t clilen = sizeof(cli_addr);
connfd = accept(listenfd, (struct sockaddr*)&cli_addr, &clilen);
// Check if max clients is reached
if ((cli_count + 1) == MAX_CLIENTS) {
printf("Max clients reached. Rejected: ");
print_client_addr(cli_addr);
printf(":%d\\n", cli_addr.sin_port);
close(connfd);
continue;
}
// Client settings
client_t *cli = (client_t *)malloc(sizeof(client_t));
cli->address = cli_addr;
cli->sockfd = connfd;
cli->uid = uid++;
// Add client to the queue and fork thread
queue_add(cli);
pthread_create(&tid, NULL, &handle_client, (void*)cli);
// Reduce CPU usage
sleep(1);
}
return EXIT_SUCCESS;
}
Õâ¶Î´úÂëÀí½âÄѶȲ»´ó£¬Ê×ÏÈ£¬·þÎñ¶Ë°ó¶¨ÔÚÒ»¸ö¶Ë¿ÚÉÏ£¬È»ºóµÈ´ý¿Í»§¶ËµÄÁ¬½Ó£¬Ò»µ©Óпͻ§¶ËÁ¬½ÓÉÏÀ´£¬¾Í½«´Ë¿Í»§¶Ë¼ÓÈëµ½¶ÓÁÐÀïÃ棬ËæºóÁ¢ÂíÆðÒ»¸öÏß³ÌȥרÃÅΪËû×öÏûÏ¢ÊÕ·¢Óá£
½Ó×Å¿´¿Í»§¶ËµÄʵÏÖ£ºclient.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <pthread.h>
#define LENGTH 2048
// Global variables
volatile sig_atomic_t flag = 0;
int sockfd = 0;
char name[32];
void str_overwrite_stdout() {
printf("\\r%s", "> ");
fflush(stdout);
}
void str_trim_lf (char* arr, int length) {
int i;
for (i = 0; i < length; i++) { // trim \\n
if (arr[i] == '\\n') {
arr[i] = '\\0';
break;
}
}
}
void catch_ctrl_c_and_exit(int sig) {
flag = 1;
}
void send_msg_handler() {
char message[LENGTH] = {};
char buffer[LENGTH + 32] = {};
while(1) {
str_overwrite_stdout();
fgets(message, LENGTH, stdin);
str_trim_lf(message, LENGTH);
if (strcmp(message, "exit") == 0) {
break;
} else {
sprintf(buffer, "%s: %s\\n", name, message);
send(sockfd, buffer, strlen(buffer), 0);
}
bzero(message, LENGTH);
bzero(buffer, LENGTH + 32);
}
catch_ctrl_c_and_exit(2);
}
void recv_msg_handler() {
char message[LENGTH] = {};
while (1) {
int receive = recv(sockfd, message, LENGTH, 0);
if (receive > 0) {
printf("%s", message);
str_overwrite_stdout();
} else if (receive == 0) {
break;
} else {
// -1
}
memset(message, 0, sizeof(message));
}
}
int main(int argc, char **argv){
if(argc != 3){
printf("Usage: %s <ip> <port>\\n", argv[0]);
return EXIT_FAILURE;
}
char *ip = argv[1];
int port = atoi(argv[2]);
signal(SIGINT, catch_ctrl_c_and_exit);
printf("Please enter your name: ");
fgets(name, 32, stdin);
str_trim_lf(name, strlen(name));
if (strlen(name) > 32 || strlen(name) < 2){
printf("Name must be less than 30 and more than 2 characters.\\n");
return EXIT_FAILURE;
}
struct sockaddr_in server_addr;
// Socket settings
sockfd = socket(AF_INET, SOCK_STREAM, 0);
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr(ip);
server_addr.sin_port = htons(port);
// Connect to Server
int err = connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
if (err == -1) {
printf("ERROR: connect\\n");
return EXIT_FAILURE;
}
// Send name
send(sockfd, name, 32, 0);
printf("=== WELCOME TO THE CHATROOM ===\\n");
pthread_t send_msg_thread;
if(pthread_create(&send_msg_thread, NULL, (void *) send_msg_handler, NULL) != 0){
printf("ERROR: pthread\\n");
return EXIT_FAILURE;
}
pthread_t recv_msg_thread;
if(pthread_create(&recv_msg_thread, NULL, (void *) recv_msg_handler, NULL) != 0){
printf("ERROR: pthread\\n");
return EXIT_FAILURE;
}
while (1){
if(flag){
printf("\\nBye\\n");
break;
}
}
close(sockfd);
return EXIT_SUCCESS;
}
¿Í»§¶ËµÄ´úÂëÒ²±È½ÏÈÝÒ×Àí½â£¬Á÷³ÌºÜ¼òµ¥£¬¿Í»§¶Ë¾ÍÊǼÓÈëµ½·þÎñ¶Ë£¬È»ºó´´½¨Ò»¸öÏß³ÌÀ´×öÏûÏ¢µÄÊÕ·¢¹¤×÷£¬Ö¸µ¼½ÓÊÕµ½Í˳öµÄÐźţ¬²ÅÖÕÖ¹Õû¸ö´óµÄ loop¡£
˵ÁËÕâô¶à£¬ÈÃÎÒÃÇÀ´ÔËÐеÄÊÔÊÔ°É£¡
Õâ¶ùÊÇ·þÎñ¶Ë³ÌÐòÆô¶¯£¬²»¹ýÎÒºóÃæ¸ø³öÁ˼¸¸ö¿Í»§¶ËÁ¬½Ó¹ýÀ´µÄ´òÓ¡¡£
Ëæºó£¬¿´¿Í»§¶Ë·½Ã棺Óû§ A µÄ¿Í»§¶Ë
Óû§ B µÄ¿Í»§¶Ë
Óû§ C µÄ¿Í»§¶Ë
´Ëʱ£¬ÎÒÃÇ·¢ÏÖ£¬ userA·¢Ë͵ÄÏûÏ¢£¬userB£¬userC ¶¼ÊÕµ½ÁË£¬±ð׿±£¬ÕâÊÇÕý³£µÄ£¬ÒòΪ£¬ÎÒÃÇ
// Send message to all clients except the sender
void send_message(char *s, int uid) {
pthread_mutex_lock(&clients_mutex);
for (int i = 0; i < MAX_CLIENTS; ++i) {
if (clients[i]) {
if (clients[i]->uid != uid) {
if (write(clients[i]->sockfd, s, strlen(s)) < 0) {
perror("ERROR: write to descriptor failed");
break;
}
}
}
}
pthread_mutex_unlock(&clients_mutex);
}
Õâ¶ÎÂß¼¾ÍÊÇ·þÎñ¶Ë»á½«ËùÓеÄÏûÏ¢¹ã²¥µ½·ÇÏûÏ¢·¢ËÍ·½£¬ËùÒÔ£¬ÎÒÃÇÐèÒªÔÚÕâÀï¼ÌÐøÓÅ»¯Ò»Ï£º
ҪʵÏÖÕâ¸öÌØÐÔ£¬ÎÒÃÇÐèÒªÔÚ·þÎñÆ÷¶Ë½øÐÐÐ޸ģ¬ÒÔ±ãËüÄܹ»½âÎö /msg <recipient_name> <message>
¸ñʽµÄÏûÏ¢£¬²¢½«ÏûÏ¢·¢Ë͸øÖ¸¶¨µÄ½ÓÊÕÕß¡£
int find_client_sockfd(const char *recipient_name, Client *clients, int max_clients) {
for (int i = 0; i < max_clients; i++) {
if (clients[i].sockfd != 0 && strcmp(clients[i].name, recipient_name) == 0) {
return clients[i].sockfd;
}
}
return -1;
}
½ÓÏÂÀ´£¬ÎÒÃÇÐèÒªÐ޸ķþÎñÆ÷µÄÏûÏ¢´¦Àí²¿·Ö£¬ÒÔ±ãËüÄܹ»Ê¶±ð˽ÃÜÏûÏ¢²¢½«Æä·¢Ë͸øÕýÈ·µÄ½ÓÊÕÕߣ¬Æª·ùÓÐÏÞ£¬¸ø³öÖ÷ҪʵÏÖ£¬Ôö¼ÓµÄ²¿·Ö£¬·¢ÏÖÊÇ˽ÃÜÏûÏ¢£¬¾Í×ßÕâ¶ÎÂß¼£¬·ñÔò¾Í°´ÕÕÖ±½ÓµÄ·½Ê½¹ã²¥¡£
// ¼ì²éÊÇ·ñΪ˽ÃÜÏûÏ¢
if (strncmp(msg, "/msg ", 5) == 0) {
char recipient_name[32];
char *message;
// ½âÎöÏûÏ¢
message = msg + 5; // Ìø¹ý "/msg "
sscanf(message, "%s", recipient_name);
message = strstr(message, " ") + 1; // Ìø¹ý½ÓÊÕÕßÃû×Ö
// ²éÕÒ½ÓÊÕÕßµÄÌ×½Ó×Ö
int recipient_sockfd = find_client_sockfd(recipient_name, clients, max_clients);
if (recipient_sockfd != -1) {
// ·¢ËÍ˽ÃÜÏûÏ¢¸ø½ÓÊÕÕß
sprintf(buffer, "[Private] %s", message);
send(recipient_sockfd, buffer, strlen(buffer), 0);
} else {
// ½ÓÊÕÕß²»´æÔÚ£¬·¢ËÍ´íÎóÏûÏ¢¸ø·¢ËÍÕß
sprintf(buffer, "User %s does not exist.\\n", recipient_name);
send(client_sockfd, buffer, strlen(buffer), 0);
}
}
ok£¬Õû¸öʵÏÖ¾ÍÍê³ÉÁË£¬ÕâÑù£¬ÎÒÃǾÍʵÏÖÁËÒ»¸öÖÐÐÄ»¯µÄ ÁÄÌì·þÎñ¡£
ËäÈ»ÎÒÃÇʵÏÖÁËÒ»¸öÖÐÐÄ»¯µÄÁÄÌì·þÎñ£¬µ«ÊÇÕâ¸öÀëÏßÉÏ¿ÉÔËÓª»¹ÊÇÓкܴóµÄ¾àÀëµÄ£¬Õâ¸öÀý×ӷdz£»ù´¡£¬Ã»ÓдíÎó´¦Àí£¬Ò²Ã»ÓмÓÃÜͨÐÅ£¬ÔÚÉú²ú»·¾³ÖУ¬ÄãÐèÒª¿¼ÂǸü¶àµÄ´íÎó´¦Àí¡¢°²È«ÐÔ¡¢ÐÔÄÜÓÅ»¯£¨±ÈÈçʹÓÃÏ̳߳ػòÕßʼþÇý¶¯µÄIOÄ£ÐÍ£©ÒÔ¼°ÆäËûµÄ¸ß¼¶ÌØÐÔ¡£ÔÙÕߣ¬Õâ¸öÊÇÒ»¸öÍêÈ«ÔÚÄÚ´æÖеÄÅܵÄÄ£ÐÍ£¬¶ÏµçÖ®ºó£¬ÁÄÌìÏûÏ¢£¬ºÃÓѹØϵȫ²¿¶¼Ã»ÓÐÁË£¬¶øÇÒÎÒÃÇ»ù´¡°æ±¾µÄÁÄÌìÊÒÀïÃ棬ºó¼ÓÈëµÄС»ï°é²»ÄܽÓÊÕ֮ǰ´ó¼Ò¶¼ÁÄÁËЩɶ£¬Õâ¶àÉÙ»¹²îÄÇôµãÒâ˼£¬ËùÒÔ£¬½»¸øÄãÀ´¼ÌÐøÍêÉÆ£¬Äã»áÓÐ˼·Âð£¿
¶øÇÒ£¬×÷Ϊ°Î¸ß£¬²»·À˼¿¼Ò»Ï£¬ÈçºÎ»ùÓÚ´Ë£¬ÊµÏÖÒ»¸öÈ¥ÖÐÐÄ»¯µÄÁÄÌì·þÎñÄØ£¿ÌáʾÏ£¬×î¼òµ¥µÄÊÇ£¬¶Ë¼È¿ÉÒÔÊÇÒ»¸ö·þÎñ¶ËÒ²¿ÉÒÔ°çÑÝÒ»¸ö¿Í»§¶Ë¡£ÔòÑù A ºÍ B ¾ÍÎÞÐèÒ»¸ö¹Ì¶¨µÄ·þÎñ¶ËÁË¡£
Ô´´ÉùÃ÷£º±¾ÎÄϵ×÷ÕßÊÚȨÌÚѶÔÆ¿ª·¢ÕßÉçÇø·¢±í£¬Î´¾Ðí¿É£¬²»µÃתÔØ¡£
ÈçÓÐÇÖȨ£¬ÇëÁªÏµ cloudcommunity@tencent.com ɾ³ý¡£
Ô´´ÉùÃ÷£º±¾ÎÄϵ×÷ÕßÊÚȨÌÚѶÔÆ¿ª·¢ÕßÉçÇø·¢±í£¬Î´¾Ðí¿É£¬²»µÃתÔØ¡£
ÈçÓÐÇÖȨ£¬ÇëÁªÏµ cloudcommunity@tencent.com ɾ³ý¡£