一,准备
- 网络编程+多线程+线程同步实现群聊架构(CS架构):客户端和服务器
- 群聊对于客户端是1对1,对于服务端是1对多。
- 头文件准备:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>
#include <semaphore.h>
二,服务端
int clnt_socks[100] = { 0 };
int clnt_cnt = 0;
pthread_mutex_t mutex;
sem_t semid;
void sev_send_msg(const char* msg, ssize_t str_len)
{
pthread_mutex_lock(&mutex);
for (int i = 0; i < clnt_cnt; i++)
{
if (clnt_socks[i] >= 0)
{
write(clnt_socks[i], msg, str_len);
}
}
pthread_mutex_unlock(&mutex);
}
void* handle_clnt(void* arg)
{
pthread_detach(pthread_self());
int clnt_sock = *(int*)arg;
char msg[1024] = "";
ssize_t str_len = 0;
while ((str_len = read(clnt_sock, msg, sizeof(msg))) > 0)
{
sev_send_msg(msg, str_len);
} ;
pthread_mutex_lock(&mutex);
*(int*)arg = -1;
pthread_mutex_unlock(&mutex);
close(clnt_sock);
pthread_exit(NULL);
}
void thread_more_server()
{
int serv_sock, clnt_sock;
struct sockaddr_in serv_adr, clnt_adr;
socklen_t clnt_adr_sz = sizeof(clnt_adr);
serv_sock = socket(PF_INET, SOCK_STREAM, 0);
if (serv_sock == -1)
{
printf("create socket error:%d %s\n", errno, strerror(errno));
return;
}
memset(&serv_adr, 0, sizeof(serv_adr));
serv_adr.sin_family = AF_INET;
serv_adr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_adr.sin_port = htons(9527);
pthread_mutex_init(&mutex, NULL);
if (bind(serv_sock, (struct sockaddr*)&serv_adr, sizeof(serv_adr)) == -1)
{
error_handling("thread server bind error");
printf("bind error msg:%d %s\n", errno, strerror(errno));
return;
}
if (listen(serv_sock, 5) == -1)
{
error_handling("thread server listen error");
printf("listen error msg:%d %s\n", errno, strerror(errno));
return;
}
printf("open thread server success!\n");
while (true)
{
clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_adr, &clnt_adr_sz);
if (clnt_sock == -1)
{
printf("accept error msg:%d %s\n", errno, strerror(errno));
break;
}
pthread_mutex_lock(&mutex);
clnt_socks[clnt_cnt++] = clnt_sock;
pthread_mutex_unlock(&mutex);
pthread_t thread;
pthread_create(&thread, NULL, handle_clnt, &clnt_socks[clnt_cnt - 1]);
printf("accept client count:%d", clnt_cnt - 1);
}
close(serv_sock);
pthread_mutex_destroy(&mutex);
}
三,客户端
char name[64] = "[MOON]";
void* client_send_msg(void* arg)
{
pthread_detach(pthread_self());
int clnt_sock = *(int*)arg;
char msg[256] = "";
char buffer[1024];
while (1)
{
memset(buffer, 0, sizeof(buffer));
fgets(msg, sizeof(msg), stdin);
if (strcmp(msg, "q\n") == 0 || (strcmp(msg, "Q\n") == 0)) {
break;
}
if (strcmp(msg, "") == 0)
{
continue;
}
snprintf(buffer, sizeof(buffer), "%s: %s", name, msg);
size_t len = strlen(buffer);
size_t send_len = 0;
while (send_len < len)
{
ssize_t ret = write(clnt_sock, buffer + send_len, len - send_len);
if (ret <= 0) {
fputs("may be connect newwork failed,make client write failed!\n", stdout);
break;
}
send_len += (size_t)ret;
}
};
sem_post(&semid);
pthread_exit(NULL);
}
void* client_recv_msg(void* arg)
{
pthread_detach(pthread_self());
int clnt_sock = *(int*)arg;
char buffer[1024] = "";
while (1)
{
size_t ret = read(clnt_sock, buffer, sizeof(buffer));
if (ret <= 0) {
fputs("client read failed!\n", stdout);
break;
}
fputs(buffer, stdout);
memset(buffer, 0, ret);
};
sem_post(&semid);
pthread_exit(NULL);
}
void thread_more_client()
{
struct sockaddr_in clnt_adr;
socklen_t clnt_adr_sz = sizeof(clnt_adr);
int clnt_sock = socket(PF_INET, SOCK_STREAM, 0);
memset(&clnt_adr, 0, clnt_adr_sz);
clnt_adr.sin_family = AF_INET;
clnt_adr.sin_addr.s_addr = inet_addr("127.0.0.1");
clnt_adr.sin_port = htons(9527);
if (connect(clnt_sock, (struct sockaddr*) & clnt_adr, clnt_adr_sz) == -1)
{
printf("connect error msg:%d %s\n", errno, strerror(errno));
return;
}
pthread_t thread_send, thread_recv;
sem_init(&semid, 0, -1);
pthread_create(&thread_send, NULL, client_send_msg, &clnt_sock);
pthread_create(&thread_recv, NULL, client_recv_msg, &clnt_sock);
sem_wait(&semid);
close(clnt_sock);
}
四,调用示例
void thread_more_cs_connect(char*arg)
{
if (strcmp(arg, "s") == 0)
{
thread_more_server();
}
else
{
fputs("Please input your name:", stdout);
scanf("%s", name);
thread_more_client();
}
}
int main(int argc, char* argv[])
{
printf("%s %s!\n", "Welcome LinuxConsoleApp_server", __func__);
thread_more_cs_connect(argv[1]);
return 0;
}
五,结果
- 实现群聊服务