gcc 4.6.0 c89
我有客户端服务器应用程序的类型。服务器在事件循环中等待来自客户端的事件的一些代码。
这不是将使用UDP/TCP套接字的客户端服务器。但是客户端和服务器将在同一台linux机器上运行。我想这就像app1与运行在同一服务器上的app2对话。
我知道我需要使用函数指针(回调),并且我需要在客户端应用程序中注册回调。服务器将等待来自客户端的事件,并相应地采取行动。
所以我在服务器上的设计是这样的:
while(running) {
switch(event) {
case START_SDL:
/* DO something */
break;
case DELETE_EDL:
/* Do something */
break;
}
}
这样,服务器就在循环中运行,等待从客户端接收事件。然而,我不知道如何开始。
非常感谢您的任何建议,
您应该使用一个工作线程来等待来自主线程的事件并对其进行处理。这是一个很长的答案,为了避免时间过长,我将省略错误检查,尽管这违反了第六条戒律。
任务结构和队列
制作一个指定任务的结构。我将使用通用的get_task
和push_task
函数在一个真实的例子中,应该使用tasks
的线程安全队列,但这会使答案变得毫无用处。我只是从我手头的旧程序中勾画出来的。
struct task {
/* function callback */
void (*fun)(void *);
/* parameter to pass to callback */
void *arg;
};
同步
使用互斥锁来保护任务队列,使用信号量来表示有工作要做。请看我上面用粗体写的内容。
/* this has to be initialized in main */
sem_t sem;
pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
工人功能
worker函数只是等待并在收到通知时执行任务。
static void *worker(void *arg)
{
struct task t;
/* detach */
pthread_detach(pthread_self());
/* loop forever */
while (1) {
/* block until we have work to do */
sem_wait(&sem);
/* we've got work to do */
pthread_mutex_lock(&mtx);
/* get the task */
t = get_task();
pthread_mutex_unlock(&mtx);
/* we are safe now, nobody can touch t */
/* execute the callback - here is your function pointer*/
(*t.fun)(t.arg);
}
return NULL;
}
主要功能
主要功能的作用是初始化内容和推送任务。
pthread_t t1;
/* initialize unnamed semaphore */
sem_init(&sem, 0, 0);
/* start worker thread */
if (0 != pthread_create(&t1, NULL, worker, NULL)) {
perror("pthread_create");
exit(1);
}
推送任务
此时,工作线程正在等待可以从main推送的任务。
pthread_mutex_lock(&mtx);
push_task(my_task);
pthread_mutex_unlock(&mtx);
这个服务器怎么会知道客户端正在触发事件?这是由你决定的,有很多方法可以在Unix上进行IPC。我的建议是使用消息队列。
服务器消息队列示例
#define MSGSIZE 1024
int main()
{
mqd_t mq;
struct mq_attr attr;
char message[MSGSIZE];
int read_bytes;
attr.mq_maxmsg = 10;
attr.mq_msgsize = MSGSIZE;
mq = mq_open("/queue", O_RDWR | O_CREAT, 0700, &attr);
if ((mqd_t)-1 == mq) {
perror("mq_open");
exit(1);
}
while (1) {
/* get message from queue */
read_bytes = mq_receive(mq, message, MSGSIZE, NULL);
if (-1 == read_bytes) {
perror("mq_receive");
exit(1);
}
/* do what you wish with the message */
}
}
因此,在"为所欲为"部分,您可以调用解释事件类型并将其推送给工作者。从客户那里发送消息非常相似,所以我不会发布(如果你真的做不到,就问问)。
这些都只是一个大谜题中的(可能是破碎的)部分。你的任务是把它们组装成你正在建造的任何东西。
除非这是一项家庭作业,否则我建议使用许多可用的IPC库之一:
- libassuan是非常轻量级和安全的,用于GnuPG组件之间
- libdbus,Unix上的标准(桌面)IPC库
- 任何数量的CORBA实现,例如MICO、TAO或omniORB
- 任何数量的MPI实现,例如LAM(现在的OpenMPI)
在*nix上,
我建议使用select()或poll(),或者,如果你真的想的话,使用线程。
在窗口上,这是一个很好的指导Winsock API。我对Windows编程不是很有经验,但据我所知,Winsocks是低级别套接字IO的方法。
编辑;
我看到了评论,很明显你在使用Linux和线程。
首先,让我告诉你,线程不容易使用,因为你必须防止两个线程同时访问相同的数据,等等。
然而,这绝对是可能的。
如果你只是作为一个学习练习来做这件事,我建议你制作一个集中的数据集(所有线程都可以访问),它是互斥的,并为每个连接创建一个线程。
如果你在生产环境中,事情就不那么容易了。首先,我建议你读一下这篇文章。然后,考虑线程池。基本上,您从一堆线程(即池)开始,然后边执行边完成任务。在维基百科上可以找到一个非常好的描述。而且,我链接的PDF也显示了其他方式。
如果你看完这些之后不想使用线程,我仍然建议选择()和poll(),它们非常容易使用。
考虑到您有基本的pthread工作,实际的代码本身应该非常简单。
一个服务器进程和一个客户端进程。。看起来像生产者和消费者的关系。这用管子很容易处理。
bash# client | server
客户端将事件写入stdout,服务器从stdin读取。如果您需要不止一个客户端,请参阅mmutz的答案
我对C或C++了解不多,但在java中,我会使用Future Task和非阻塞IO的组合来解决这个问题。请看一看,只是想找个主意。