关于多线程,多消息队列做一个UDP并发服务器

linyangwo2008 2010-10-28 01:45:52
首先用epoll检测套接字状态,虽然UDP只有一个套接字,但是用了epoll可以大大降低cpu的使用,得到数据后,想用一个线程池+多个消息队列来处理,现在只能做到单线程+单个消息队列,求高人指点:
heart_beat_packet.h:
struct MSHeartBeatUDPPacket
{
char SN[32];
int ms_id;
int tag;
char localIP[16];
char flag;
char reserved[67];
}__attribute__((packed));

struct RSP_MSHeartBeatUDPPacket
{
char SN[32];
int tag;
int ms_id;
char reserved[64];
}__attribute__((packed));
memery_struct.h:
struct momery_struct
{
char localIP[16];
char router_ip[16];
int port;
int seconds;
}__attribute__((packed));

struct res_mom
{
char SN[32];
char localIP[16];
char router_ip[16];
int tag;
int port;
int ms_id;
char flag;
char reserved[3];
}__attribute__((packed));

struct block_queue
{
struct res_mom cli_address;
struct sockaddr_in client;
long size;
struct list_head list;
}__attribute__((packed));

server.c:
#include <mysql/mysql.h>
#include "list.h"
#include <pthread.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/msg.h>
#include <time.h>
#include <pthread.h>
#include <sys/time.h>
#include <errno.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include "heart_beat_packet.h"
#include "global.h"
#include "momery_struct.h"
#include <sys/epoll.h>

#define MAX_EVENTS 5000

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

struct tm *timeinfo;
struct momery_struct user[10000];

int ep,counter = 0;
MYSQL mysql;
MYSQL_RES *res;
MYSQL_ROW row;
char query[512] = {0};

int listenfd;

char *hostname = NULL;
char *username = NULL;
char *password = NULL;
char *database = NULL;
struct list_head head;

void setnonblocking(int sock)
{
int opts;
opts = fcntl(sock, F_GETFL);

if (opts < 0)
{
perror("fcntl(sock,GETFL)");
exit(1);
}

opts = opts | O_NONBLOCK;

if (fcntl(sock, F_SETFL, opts) < 0)
{
perror("fcntl(sock, SETFL, opts)");
exit(1);
}
}

int refreshtime()
{
time_t nowtime;
time(&nowtime);
timeinfo = localtime(&nowtime);
return nowtime;
}

void scan(void *cli_address, void *client)
{

struct res_mom *cli_addr = (struct res_mom *)cli_address;
struct sockaddr_in *cli = (struct sockaddr *)client;

if (cli_addr -> ms_id == 0)
{
//printf("buf.SN: %s\n", cli_addr -> SN);
db_insert(cli_addr, cli);
}

else if(check_momery(cli_addr) == 0)
{
//printf("check momery\n");
db_update(cli_addr, cli);
}

else
{
//printf("momery update\n");
momery_update(cli_addr,cli);
}

/*for(count = 0; count < 10000; count++)
{
if (user[count].seconds != 0)
{
if ((refreshtime() - user[count].seconds) >= 60)
db_set_flag(count, cli_addr);
}
}*/
}

int handle_message(void *cli_addr, void *client)
{
return insert_queue(cli_addr, client);
}

int insert_queue(void *cli_addr, void *client)
{
struct block_queue *b = (struct block_queue *)malloc(sizeof(struct block_queue));

memcpy(&(b -> cli_address), (struct res_mom *)cli_addr, 80);
memcpy(&(b -> client), (struct sockaddr_in *)client, sizeof(struct sockaddr_in));
pthread_mutex_lock(&mutex);

if (counter > 1000)
return 1;

else
counter++;
list_add_tail(&b->list, &head);

pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);

return 0;
}

static void block_que()
{
struct res_mom cli_addr;
struct sockaddr_in client;
struct block_queue *head_node;

for( ; ;)
{
pthread_mutex_lock(&mutex);
pthread_cond_wait(&cond, &mutex);
if (list_empty(&head))
{
pthread_mutex_unlock(&mutex);
continue;
}

else
{
memset(&cli_addr, 0 , sizeof(cli_addr));
head_node = list_entry(head.next, struct block_queue, list);
memcpy(&cli_addr, &(head_node -> cli_address), 80);
memcpy(&client, &(head_node -> client), sizeof(client));
list_del(&head_node -> list);
free(head_node);
counter--;
}

pthread_mutex_unlock(&mutex);

scan(&cli_addr, &client);

}
}

static int init_threads()
{
size_t i = 0;

pthread_t child_thread;
pthread_attr_t child_thread_attr;
pthread_attr_init(&child_thread_attr);
pthread_attr_setdetachstate(&child_thread_attr, PTHREAD_CREATE_DETACHED);

if (pthread_create(&child_thread, &child_thread_attr, (void *)block_que, NULL) < 0)
{
SYSLOG("pthread_create Failed: %s\n", strerror(errno));
return 1;
}
else
{
return 0;
}
}

int main(int argc, char *argv[])
{
memset(user, 0 , sizeof(struct momery_struct)*10000);
pthread_t id;
int sockfd, i, nfds, g_epollfd;
struct sockaddr_in serv;
int pid;
int port;
int now_seconds = 0;
int count = 0;

int serv_port = 9000;
int opt = -1, daemon = 0;

mysql_init(&mysql);
mysql_options(&mysql, MYSQL_READ_DEFAULT_GROUP, "mysql");

if (!mysql_real_connect(&mysql, "localhost", "root", "123456", "zhudewei", 0 , NULL, 0))
{
SYSLOG("can not connect to mysql\n");
exit(-1);
}

INIT_LIST_HEAD(&head);


struct epoll_event ev, events[MAX_EVENTS];
g_epollfd = epoll_create(MAX_EVENTS);

listenfd = socket(AF_INET, SOCK_DGRAM, 0);
if (listenfd < 0) {
perror("socket");
exit(1);
}

setnonblocking(listenfd);

memset(&serv,0,sizeof(serv));
serv.sin_family = AF_INET;
serv.sin_port = htons(serv_port);
serv.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(listenfd, (struct sockaddr*)&serv, sizeof(serv)) < 0) {
perror("bind");
exit(1);
}

if (init_threads() == 0)
{
SYSLOG("Sucess init threads\n");

}

ev.data.fd = listenfd;
ev.events = EPOLLIN | EPOLLET;
epoll_ctl(g_epollfd, EPOLL_CTL_ADD, listenfd, &ev);


now_seconds = refreshtime();
int curfds = 1;
while (1) {
if((refreshtime() - now_seconds) >= 60)
{
now_seconds = refreshtime();
for(count = 0; count < 10000; count++)
{
if (user[count].seconds != 0)
{
if ((refreshtime() - user[count].seconds) >= 60)
db_set_flag(count);
}
}
}

nfds = epoll_wait(g_epollfd, events, MAX_EVENTS, -1);
if (nfds == 0)
continue;
else if(nfds < 0)
{
SYSLOG("epoll_wait error\n");
}
else
{
for (i = 0; i < nfds; i++)
{
if (events[i].events & EPOLLIN)
{
struct MSHeartBeatUDPPacket buf;
struct sockaddr_in cli;
socklen_t addrlen;
int n;
struct res_mom cli_address;
struct RSP_MSHeartBeatUDPPacket packet;
memset(&cli_address, 0, sizeof(struct res_mom));

memset(&packet, 0, sizeof(packet));
memset(&cli, 0, sizeof(cli));
addrlen = sizeof(cli);
memset(&buf, 0, sizeof(buf));

n = recvfrom(events[i].data.fd, &buf, sizeof(buf), 0, (struct sockaddr*)&cli, &addrlen);
if (n < 0)
continue;

memset(&cli_address, 0, sizeof(struct res_mom));
cli_address.port = cli.sin_port;
cli_address.ms_id = buf.ms_id;
cli_address.tag = buf.tag;
cli_address.flag = buf.flag;
strcpy(cli_address.localIP, buf.localIP);
strcpy(cli_address.router_ip, inet_ntoa(cli.sin_addr));
strcpy(cli_address.SN, buf.SN);

/*if (buf.flag & FLAG_MUST_REPLY)
{
packet.tag = buf.tag;
packet.ms_id = buf.ms_id;
strcpy(packet.SN, buf.SN);
sendto(events[i].data.fd, &packet, sizeof(packet), 0, (struct sockaddr*)&cli, sizeof(cli));
}*/

//int ret = 0;
if(handle_message(&cli_address, &cli) != 0)
SYSLOG("handler ret != 0");

/*if (buf.flag & FLAG_MUST_REPLY)
{
packet.tag = buf.tag;
packet.ms_id = buf.ms_id;
printf("buf.ms_id: %d\n",buf.ms_id);
strcpy(packet.SN, buf.SN);
sendto(events[i].data.fd, &packet, sizeof(packet), 0, (struct sockaddr*)&cli, sizeof(cli));
}*/
/*if (ret != 0 && errno != 11)
{
epoll_ctl(g_epollfd, EPOLL_CTL_DEL, events[i].data.fd, &ev);
curfds--;
}*/
}
}
}
}
close(listenfd);
mysql_close(&mysql);
}

...全文
646 2 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
2 条回复
切换为时间正序
请发表友善的回复…
发表回复
linyangwo2008 2010-10-28
  • 打赏
  • 举报
回复
再补充下,不是单线程加消息队列不可以,而是因为cpu是多核,所以如果要发挥多核的优势,用N线程+N消息队列很好!但我不知道怎么去实现!
linyangwo2008 2010-10-28
  • 打赏
  • 举报
回复
部分具体函数功能就不写了,帖子过长

23,217

社区成员

发帖
与我相关
我的任务
社区描述
Linux/Unix社区 应用程序开发区
社区管理员
  • 应用程序开发区社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧