C 使用单向链表实现消息群发功能

需求与思路

需求是为了实现一个服务器N个客户端通信,并且能够实现线上群发功能。
以前开发过类似的c\s通信,但都是点对点的实现通信,现在是1对N,刚开始有点头疼,想的挺复杂。
但后来突然想到既然要实现通信,不如就先实现通信。
点对点通信很容易就实现了,就是一对一的socket,接下来就是一对多,
既然是一对多,那就使用线程来实现把,一个线程处理一个通信。
好,1对多有了,那怎么在建立起通信后再次随时发送消息呢,
注意这里必须先让客户端进行连接才能通信,不然不知道对方的ip与端口想发消息也发不出去。

单链表

说实在的,C语言必须要自己造轮子,这一点是我经常吐槽的一个点。写代码的时候多希望用python代替啊,哈哈哈。话说回来,想要存储必要的信息,并且后边还需要遍历查询并且使用,我只想到了单链表(嗯,还有python 的 list 和dict),单纯的看需求,想要记录客户端的信息单链表足够了,那么接下来造轮子吧。
//定义链表结构
struct LinkAddr
{
int data;
int server_msgfd;
struct sockaddr_in server_msg;
struct LinkAddr *next;
};
*很多人使用typedef 来定义这样也可以。
//定义一个链表结构,我这里使用的是全局的。
struct LinkAddr *link_glable;

//创建头结点,并初始化。
void init()
{
link_glable = (struct LinkAddr*)malloc(sizeof(struct LinkAddr));
if(link_glable == NULL)
{
printf(“头结点分配失败,程序终止! \n”);
}
link_glable->data=0;
link_glable->next=NULL;
memset(link_glable->imei,0,20);
link_glable=link_glable;
}

//接下来是增加节点
void append(int sock)
{
struct LinkAddr *compare = link_glable;
while(compare)
{
if(compare->data ==0)
{
compare=compare->next;
continue;
}
if((compare->server_msgfd ==sock) && (strcmp(imei,compare->imei)==0))
return;
}

struct LinkAddr * pNew = (struct LinkAddr *)malloc(sizeof(struct LinkAddr));
pNew->next =link_glable;
pNew->server_msgfd=sock;
pNew->server_msg=client_addr;
pNew->data=1;
memset(pNew->imei,0,20);
strcpy(pNew->imei,imei);
link_glable=pNew;//把新建的节点的地址赋值给link_glable,现在的链表是这样的:link_glable->head->null

}

多线程socket通信

创建线程池(参考https://blog.csdn.net/guotianqing/article/details/88929210)

thread_pool.h如下:
#include <pthread.h>

struct job {
void * (*callback_function)(void *arg);
void *arg;
struct job *next;
};

struct threadpool {
int thread_num;
int queue_max_num;
struct job *head;
struct job *tail;
pthread_t *pthreads;
pthread_mutex_t mutex;
pthread_cond_t queue_empty;
pthread_cond_t queue_not_empty;
pthread_cond_t queue_not_full;
int queue_cur_num;
int queue_close;
int pool_close;
};

struct threadpool *threadpool_init(int thread_num, int queue_max_num);

int threadpool_add_job(struct threadpool *pool, void *(*callback_function)(void *arg), void *arg);

int threadpool_destroy(struct threadpool *pool);

void *threadpool_function(void *arg);
————————————————
版权声明:本文为CSDN博主「guotianqing」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/guotianqing/article/details/88929210

thread_pool.c如下:
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

#include “thread_pool.h”

struct threadpool *threadpool_init(int thread_num, int queue_max_num)
{
struct threadpool *pool = NULL;

do {
    pool = (struct threadpool *)calloc(1, sizeof(struct threadpool));
    if (!pool) {
        printf("calloc error: %m\n");
        break;
    }
    pool->thread_num = thread_num;
    pool->queue_max_num = queue_max_num;
    pool->queue_cur_num = 0;
    pool->head = NULL;
    pool->tail = NULL;
    if (pthread_mutex_init(&(pool->mutex), NULL)) {
        printf("init mutex error: %m\n");
        break;
    }
    if (pthread_cond_init(&(pool->queue_empty), NULL)) {
        printf("init queue_empty error: %m\n");
        break;
    }
    if (pthread_cond_init(&(pool->queue_not_empty), NULL)) {
        printf("init queue_not_empty error: %m\n");
        break;
    }
    if (pthread_cond_init(&(pool->queue_not_full), NULL)) {
        printf("init queue_not_full error: %m\n");
        break;
    }
    pool->pthreads = calloc(1, sizeof(pthread_t) * thread_num);
    if (!pool->pthreads) {
        printf("calloc pthreads error: %m\n");
        break;
    }
    pool->queue_close = 0;
    pool->pool_close = 0;
    int i;
    for (i = 0; i < pool->thread_num; i++) {
        pthread_create(&(pool->pthreads[i]), NULL, threadpool_function, (void *)pool);
    }
    return pool;
} while (0);

return NULL;

}

int threadpool_add_job(struct threadpool *pool, void *(*callback_function)(void *arg), void *arg)
{
assert(pool != NULL);
assert(callback_function != NULL);
assert(arg != NULL);

pthread_mutex_lock(&(pool->mutex));
while ((pool->queue_cur_num == pool->queue_max_num) && !(pool->queue_close || pool->pool_close)) {
    pthread_cond_wait(&(pool->queue_not_full), &(pool->mutex));
}
if (pool->queue_close || pool->pool_close) {
    pthread_mutex_unlock(&(pool->mutex));
    return -1;
}
struct job *pjob = (struct job*) calloc(1, sizeof(struct job));
if (!pjob) {
    pthread_mutex_unlock(&(pool->mutex));
    return -1;
}

pjob->callback_function = callback_function;
pjob->arg = arg;
pjob->next = NULL;
if (pool->head == NULL) {
    pool->head = pool->tail = pjob;
    pthread_cond_broadcast(&(pool->queue_not_empty));
} else {
    pool->tail->next = pjob;
    pool->tail = pjob;
}

pool->queue_cur_num++;
pthread_mutex_unlock(&(pool->mutex));

return 0;

}

void *threadpool_function(void *arg)
{
struct threadpool *pool = (struct threadpool *)arg;
struct job *pjob = NULL;

while (1) {
    pthread_mutex_lock(&(pool->mutex));
    while ((pool->queue_cur_num == 0) && !pool->pool_close) {
        pthread_cond_wait(&(pool->queue_not_empty), &(pool->mutex));
    }

    if (pool->pool_close) {
        pthread_mutex_unlock(&(pool->mutex));
        pthread_exit(NULL);
    }
    pool->queue_cur_num--;
    pjob = pool->head;
    if (pool->queue_cur_num == 0) {
        pool->head = pool->tail = NULL;
    } else {
        pool->head = pjob->next;
    }

    if (pool->queue_cur_num == 0) {
        pthread_cond_signal(&(pool->queue_empty));
    }
    if (pool->queue_cur_num == pool->queue_max_num - 1) {
        pthread_cond_broadcast(&(pool->queue_not_full));
    }
    pthread_mutex_unlock(&(pool->mutex));

    (*(pjob->callback_function))(pjob->arg);
    free(pjob);
    pjob = NULL;
}

}

int threadpool_destroy(struct threadpool *pool)
{
assert(pool != NULL);
pthread_mutex_lock(&(pool->mutex));
if (pool->queue_close || pool->pool_close) {
pthread_mutex_unlock(&(pool->mutex));
return -1;
}
pool->queue_close = 1;
while (pool->queue_cur_num != 0) {
pthread_cond_wait(&(pool->queue_empty), &(pool->mutex));
}
pool->pool_close = 1;
pthread_mutex_unlock(&(pool->mutex));
pthread_cond_broadcast(&(pool->queue_not_empty));
pthread_cond_broadcast(&(pool->queue_not_full));

int i;
for (i = 0; i < pool->thread_num; i++) {
    pthread_join(pool->pthreads[i], NULL);
}

pthread_mutex_destroy(&(pool->mutex));
pthread_cond_destroy(&(pool->queue_empty));
pthread_cond_destroy(&(pool->queue_not_empty));
pthread_cond_destroy(&(pool->queue_not_full));
free(pool->pthreads);

struct job *p;
while (pool->head != NULL) {
    p = pool->head;
    pool->head = p->next;
    free(p);
}
free(pool);

return 0;

}
————————————————
版权声明:本文为CSDN博主「guotianqing」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/guotianqing/article/details/88929210

定义全局sockaddr_in 变量
struct sockaddr_in server_addr;
struct sockaddr_in client_addr;
//init server的socket接口。return 什么的自己定义就行
int init_sockfd()
{
if (( server_sockfd = socket( AF_INET , SOCK_STREAM , 0 )) < 0 )
{
printf(“Socket Failed !!!\r\n”);
event=V_SOCKET_ERROR ;
return(event);
}

server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(8901);
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);

if(bind(server_sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
{
 
	printf("bind Failed !!!\r\n");
	event=V_BIND_ERROR ;
	return(event);	 
}
if(listen(server_sockfd, 100) == -1)
{
	printf("listen Failed !!!\r\n");
	event=V_SOCKET_ERROR ;
	return(event);
}

event=V_OK;
return(event);

}

初始化完了接下来就是使用了。

主函数创建线程

int main(int argc, char **argv)
{
int flag = 1;
int client_sockfd=0;
struct threadpool *pool = threadpool_init(NUM_UNLIMIT,NUM_UNLIMIT);
init();
if(V_OK != init_sockfd())
{
printf(“init sock failed!\n”);
return -1;
}

while(1)
{

	switch (flag)
	{
		case PTHREADS_UNLIMIT:
			printf("PTHREADS_UNLIMIT......\n");
			int client_lenth=sizeof(client_addr);
			if ((client_sockfd = accept(server_sockfd, (struct sockaddr *) &client_addr, (socklen_t *) &client_lenth)) > 0)
			{
				
				printf("create pthread!\n");
				//pthread_create(&thread[pthread_count], NULL, responesEvent,);
				threadpool_add_job(pool, responesEvent, &client_sockfd);
				printf("wrisbands connect! \n");
			}				
			
			break;
		case PTHREAD_LIMIT:
			printf("PTHREAD_LIMIT......\n");
			break;
	}
}

}
//线程处理函数
void *responesEvent(void *client)
{
struct argvs * tmp =(struct argvs *)client;
int c_fd=tmp->tmp_fd;
unsigned char char_recv[MAX_BUF_LEN];

int byte=recv(c_fd,char_recv,MAX_BUF_LEN,0);
*
*处
*理
*过
*程
*
if(客户端)
append(link_glable,c_fd,imei);
else
sendband()//其他处理(群发消息机制)
}

void sendband()
{
struct LinkAddr send_link = link_glable;//链表地址赋值
while(send_link)
{
if(strstr(wris_id,send_link->imei) ==NULL )
{
send_link=send_link->next;
continue;
}
if(send_link->data ==0)
{
send_link=send_link->next;
continue;
}
connect(send_link->server_msgfd,(struct sockaddr
)&send_link->server_msg,sizeof(send_link->server_msg));
if(send(send_link->server_msgfd,back_buf,sizeof(back_buf),0) == 0)
{
printf(“send link send error!!!\n”);
return;
}
else
{
printf(“sand link send succ!!!\n”);
}

send_link=send_link->next;
}
}

参考链接

https://blog.csdn.net/guotianqing/article/details/88929210

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章