今天老师布置了一个在线聊天室用户私发消息的问题
思路:在服务端的用户链表中找到要私发的用户名,用其节点里的套接字号发消息,就可以达到私发的效果。
运行效果:
可以看到,Tom给Bill、Lily群发一个问候消息,Lily私发消息回应Tom。
客户端代码:
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
#define COMMUNICATION_PORT 55316
#define MSG_S2C_USER_QUEUE_FULL "The number of users reaches the upper bound"
#define CMD_C2S_QUIT "Quit connection"
#define CMD_C2S_OBATIN_USER_LIST "Obtain the user list from the server"
#define MSG_S2C_SEND_USER_LIST "The server is sending the user list"
#define MSG_S2C_USER_LIST_HAS_BEEN_SENT "The user information has been sent"
#define CMD_C2S_SEND_MESSAGE_TO_ALL_USERS "Send a message to all users"
#define MSG_S2C_MESSAGE_TO_ALL_USERS "The server is sending a message to all users"
// 私发
#define CMD_C2S_SEND_MESSAGE_TO_USER_PRIVATELY "Send a message to a user privately"
#define MSG_S2C_MESSAGE_TO_USER_PRIVATELY "The server is sending a message to user privately"
//the thread who receives the message sent from the server
static void * messageReceiverThread(void * arg);
int main(int argc, const char ** argv){
char buff[1024];
char message[1024];
char username[10]; // 私发的用户名字
//create the socket
int connfd = socket(AF_INET, SOCK_STREAM, 0);
if(connfd == -1){
printf("1. Create socket failed\n");
return -1;
}
struct sockaddr_in servAddr;
bzero(&servAddr, sizeof(servAddr));
servAddr.sin_family = AF_INET;
servAddr.sin_addr.s_addr = inet_addr("192.168.83.129");
servAddr.sin_port = htons(COMMUNICATION_PORT);
//connect to the sever
if (connect(connfd, (struct sockaddr *)&servAddr, sizeof(servAddr)) == -1){
printf("1. Connect failed\n");
return -1;
}
printf("1. Connected to the server!\n");
bzero(buff, sizeof(buff));
read(connfd, buff, sizeof(buff));
if(strcmp(buff, MSG_S2C_USER_QUEUE_FULL) == 0){
printf(" Message from the server: %s\n", buff);
return -1;
}
//print the welcome message
printf(" Message from the server: %s\n", buff);
//send the user name to the server
char userName[100];
bzero(userName, sizeof(userName));
printf(" Input user name: ");
fgets(userName, 100, stdin);
userName[strlen(userName) - 1] = '\0';
bzero(buff, sizeof(buff));
strcpy(buff, userName);
write(connfd, buff, strlen(buff));
//create a thread to receive messages sent from the server
pthread_t th;
pthread_create(&th, NULL, messageReceiverThread, (void *)&connfd);
int quitFlag = 1;
while(quitFlag){
printf(" Command:\n");
printf(" 1. Obtain the user list.\n");
printf(" 2. Send message to all clients.\n");
printf(" 3. Send message to the client privately.\n");
printf(" 0. Quit.\n");
printf(" Input Command:\n");
int command;
scanf("%d", &command);
getchar();
switch(command){
case 0: bzero(buff, sizeof(buff));
strcpy(buff, CMD_C2S_QUIT);
write(connfd, buff, strlen(buff));
quitFlag = 0;
break;
case 1: bzero(buff, sizeof(buff));
strcpy(buff, CMD_C2S_OBATIN_USER_LIST);
write(connfd, buff, strlen(buff));
break;
case 2: bzero(buff, sizeof(buff));
strcpy(buff, CMD_C2S_SEND_MESSAGE_TO_ALL_USERS);
write(connfd, buff, strlen(buff));
printf(" Message: ");
bzero(message, sizeof(message));
fgets(message, 1024, stdin);
message[strlen(message) - 1] = '\0';
bzero(buff, sizeof(buff));
strcpy(buff, message);
write(connfd, buff, strlen(buff));
break;
case 3:bzero(buff, sizeof(buff));
strcpy(buff, CMD_C2S_SEND_MESSAGE_TO_USER_PRIVATELY);
write(connfd, buff, strlen(buff));
printf(" Priavte Username: ");
bzero(username, sizeof(username));
fgets(username, 10, stdin);
username[strlen(username) - 1] = '\0';
bzero(buff, sizeof(buff));
strcpy(buff, username);
write(connfd, buff, strlen(buff));
printf(" Message: ");
bzero(message, sizeof(message));
fgets(message, 1024, stdin);
message[strlen(message) - 1] = '\0';
bzero(buff, sizeof(buff));
strcpy(buff, message);
write(connfd, buff, strlen(buff));
break;
default:
printf(" Unknown command!\n");
}
}
close(connfd);
printf("2. Sokcet is closed\n");
return 0;
}
static void * messageReceiverThread(void * arg){
int connfd = * (int *)arg;
char buff[1024];
while(1){
//receive message from the server
bzero(buff, sizeof(buff));
read(connfd, buff, sizeof(buff));
//the server is sending the user list
if(strcmp(buff, MSG_S2C_SEND_USER_LIST) == 0){
bzero(buff, sizeof(buff));
read(connfd, buff, sizeof(buff));
while(strcmp(buff, MSG_S2C_USER_LIST_HAS_BEEN_SENT) != 0){
printf(" Message from the server: %s\n", buff);
bzero(buff, sizeof(buff));
read(connfd, buff, sizeof(buff));
}
}
//the server is sending a message to all users
if(strcmp(buff, MSG_S2C_MESSAGE_TO_ALL_USERS) == 0){
bzero(buff, sizeof(buff));
read(connfd, buff, sizeof(buff));
printf(" %s\n", buff);
}
//the server is sending a message to user privately
if(strcmp(buff, MSG_S2C_MESSAGE_TO_USER_PRIVATELY) == 0){
bzero(buff, sizeof(buff));
read(connfd, buff, sizeof(buff));
printf(" %s\n", buff);
}
}
return NULL;
}
服务端代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <pthread.h>
#define COMMUNICATION_PORT 55316
#define MAX_CLIENTS 3
#define MSG_S2C_USER_QUEUE_FULL "The number of users reaches the upper bound"
#define MSG_S2C_WELCOME_MESSAGE "Welcome connect to the server"
#define CMD_C2S_QUIT "Quit connection"
#define CMD_C2S_OBATIN_USER_LIST "Obtain the user list from the server"
#define MSG_S2C_SEND_USER_LIST "The server is sending the user list"
#define MSG_S2C_USER_LIST_HAS_BEEN_SENT "The user information has been sent"
#define CMD_C2S_SEND_MESSAGE_TO_ALL_USERS "Send a message to all users"
#define MSG_S2C_MESSAGE_TO_ALL_USERS "The server is sending a message to all users"
// 私发
#define CMD_C2S_SEND_MESSAGE_TO_USER_PRIVATELY "Send a message to a user privately"
#define MSG_S2C_MESSAGE_TO_USER_PRIVATELY "The server is sending a message to user privately"
//struct of user node
struct userNode{
int userID;
char userName[100];
int connfd;
struct userNode * next;
};
//global variables
struct userNode * userList;
int userCount, historicalConnections;
//the child threads call this function
static void * childThread(void * arg);
int main(int argc, const char ** argv){
struct sockaddr_in clientAddr;
socklen_t len;
char buff[1024];
//initialize the golbal variables
userList = (struct userNode *)malloc(sizeof(struct userNode));
userList->next = NULL;
userCount = 0;
historicalConnections = 0;
//create the socket
int socketServer = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(socketServer == -1){
printf("1. Create socket failed.\n");
return -1;
}
printf("1. The socket is created.\n");
//bind the socket
struct sockaddr_in servAddr;
bzero(&servAddr, sizeof(servAddr));
servAddr.sin_family = AF_INET;
servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
servAddr.sin_port = htons(COMMUNICATION_PORT);
if(bind(socketServer, (struct sockaddr *)&servAddr, sizeof(servAddr)) == -1){
printf("2. Bind failed.");
return -1;
}
printf("2. The address is bound.\n");
//convert the state into listen state
if(listen(socketServer, 5) == -1){
printf("3. Listen failed.\n");
return -1;
}
printf("3. Listen state.\n");
printf("4. Waiting for connection.\n");
while(1){
//wait for connection
int connfd = accept(socketServer, (struct sockaddr *)(&clientAddr), &len);
if(connfd == -1){
printf("4. Accept failed\n");
return -1;
}
printf(" A new client is connecting to the server.\n");
if(userCount < MAX_CLIENTS){
//create the child thread
pthread_t th;
pthread_create(&th, NULL, childThread, (void *) &connfd);
}
//the number of clients reaches the upper bound
else{
printf(" The number of clients reaches the upper bound, connection is forbidden.\n");
bzero(buff, sizeof(buff));
strcpy(buff, MSG_S2C_USER_QUEUE_FULL);
write(connfd, buff, strlen(buff));
}
}
free(userList);
close(socketServer);
return 0;
}
static void * childThread(void * arg){
int connfd = * (int *)arg;
char buff[1024];
//send the welcome message
bzero(buff, sizeof(buff));
strcpy(buff, MSG_S2C_WELCOME_MESSAGE);
write(connfd, buff, strlen(buff));
//create a user node to store the information
struct userNode * cn = (struct userNode *)malloc(sizeof(struct userNode));
//insert the user node to the end of the user list
struct userNode * p = userList;
while(p->next != NULL)
p = p->next;
p->next = cn;
//obtain the user name and initialize the user node
cn->connfd = connfd;
cn->userID = historicalConnections++;
cn->next = NULL;
bzero(buff, sizeof(buff));
read(connfd, buff, sizeof(buff));
strcpy(cn->userName, buff);
printf(" New client: connfd(%d), userID(%d), userName(%s), TID(%ld)\n",
cn->connfd, cn->userID, cn->userName, pthread_self());
userCount++;
int quitFlag = 1;
while(quitFlag){
//obtain the command from the client
bzero(buff, sizeof(buff));
read(connfd, buff, sizeof(buff));
//user quits the connection
if(strcmp(buff, CMD_C2S_QUIT) == 0){
p = userList;
while(p->next != cn)
p = p->next;
p->next = cn->next;
userCount--;
quitFlag = 0;
printf(" Client: connfd(%d), userID(%d), userName(%s) quits the connection, clientCount(%d).\n",
cn->connfd, cn->userID, cn->userName, userCount);
}
//user wants to obtain the user list
if(strcmp(buff, CMD_C2S_OBATIN_USER_LIST) == 0){
printf(" message from the client(%d): %s\n", connfd, buff);
//tell the client that the server is about to send the user information
bzero(buff, sizeof(buff));
strcpy(buff, MSG_S2C_SEND_USER_LIST);
write(connfd, buff, strlen(buff));
sleep(0.1);
//fetch the user information
p = userList->next;
int clientIdx = 1;
while(p != NULL){
//send the information of all clients
bzero(buff, sizeof(buff));
sprintf(buff, "%d. userID: %d userName: %s", clientIdx++, p->userID, p->userName);
printf(" Message to the client(%d): %s\n", connfd, buff);
write(connfd, buff, sizeof(buff));
sleep(0.1);
p = p->next;
}
//tell the client that the user information have been sent
bzero(buff, sizeof(buff));
strcpy(buff, MSG_S2C_USER_LIST_HAS_BEEN_SENT);
write(connfd, buff, strlen(buff));
}
//user wants to send a message to all users
if(strcmp(buff, CMD_C2S_SEND_MESSAGE_TO_ALL_USERS) == 0){
printf(" message from the client(%d): %s\n", connfd, buff);
//receive the message
bzero(buff, sizeof(buff));
read(connfd, buff, sizeof(buff));
char message[2048];
bzero(message, sizeof(message));
sprintf(message, "Message from %s to all users: %s", cn->userName, buff);
//send message to all users
p = userList->next;
while(p != NULL){
if(p->connfd != connfd){
bzero(buff, sizeof(buff));
strcpy(buff, MSG_S2C_MESSAGE_TO_ALL_USERS);
write(p->connfd, buff, strlen(buff));
sleep(0.1);
write(p->connfd, message, strlen(message));
printf(" Send message from %s to %s\n", cn->userName, p->userName);
sleep(0.1);
}
p = p->next;
}
}
//user wants to send a message to user privately
if(strcmp(buff, CMD_C2S_SEND_MESSAGE_TO_USER_PRIVATELY) == 0){
printf(" message from the client(%d): %s\n", connfd, buff);
//receive the username
bzero(buff, sizeof(buff));
read(connfd, buff, sizeof(buff));
char username[10];
bzero(username, sizeof(username));
strcpy(username, buff);
//receive the message
bzero(buff, sizeof(buff));
read(connfd, buff, sizeof(buff));
char message[2048];
bzero(message, sizeof(message));
sprintf(message, "Message from %s to %s privately: %s", cn->userName, username, buff); // 把消息写入到 message 句柄中,待发送
//send message to the user privately
p = userList->next;
while(p != NULL){
if(strcmp(p->userName, username) == 0){ // 寻找指定的私发用户
bzero(buff, sizeof(buff));
strcpy(buff, MSG_S2C_MESSAGE_TO_USER_PRIVATELY);
write(p->connfd, buff, strlen(buff));
sleep(0.1);
write(p->connfd, message, strlen(message));
printf(" Send message from %s to %s privately\n", cn->userName, p->userName);
sleep(0.1);
break;
}
p = p->next;
}
}
}
close(connfd);
free(cn);
return NULL;
}
标签:聊天室,sizeof,bzero,发消息,unix,printf,connfd,message,buff
From: https://blog.csdn.net/m0_74054477/article/details/143219138