linux中select函數 實現多用戶通信

Select服務器實現多人通信的原理:

 


用戶與服務器之間需要動態建立三條管道,第一條管道用於判斷用戶是否上線,如果用戶n上線則在server.fifo中寫入on以及用戶id,然後建立專門用來發信息和收信息的管道,並將用戶n加入用戶鏈表。用戶n通過發信息管道向服務器發信息,服務器收到信息後,將信息發送給目前在線的所有用戶。用戶個數即鏈表中結點個數。

 

代碼如下:

 

1、頭文件

 

#ifndef __SER_H__

#define __SER_H__

#include<stdio.h>

#include<stdlib.h>

#include<string.h>

#include<unistd.h>

#include<sys/stat.h>

#include<sys/types.h>

#include<fcntl.h>

#include<sys/select.h>

#include<sys/time.h>

#define PIPE_PATH "/home/comst/pipe"

#define PIPE_NAME "server.fifo"

typedef struct tag

{

int m_id ;

int m_send;

int m_recv;

struct tag* m_next ;

}CLIENT, *pCLIENT;

void distpatch_msg(pCLIENT phead, char* msg);

#endif

 

2、服務器server.c

/*************************************************************************

  > File Name: ./src/server.c

  > Author: Comst

  > Mail:[email protected] 

  > Created Time: Sun 01 Feb 2015 04:41:48 PM CST

 ************************************************************************/

#include"my_server.h"

 

int main(int argc, char* argv[])

{

int fd_listen ;

char path_name[128] = "" ;

char fifo_name[128] ;

char msg[1024];

 

char client_stat[5]  = "";

int client_pid ;

sprintf(path_name, "%s/%s", PIPE_PATH, PIPE_NAME);

 

mkfifo(path_name, 0666);

 

printf("mkfifo over!\n");

 

fd_listen = open(path_name, O_RDONLY);

if(fd_listen == -1)

{

printf("open server_fifo fail!\n");

exit(1);

}

pCLIENT plist = NULL, pcur, pnew, ppre ;

 

fd_set rd_sets, bak_sets;

FD_ZERO(&rd_sets);

FD_ZERO(&bak_sets);

 

FD_SET(fd_listen, &rd_sets);

while(1)

{

bak_sets = rd_sets ;

printf("selecting...\n");

select(1024, &bak_sets, NULL, NULL, NULL);

 

if(FD_ISSET(fd_listen, &bak_sets))

{

memset(msg,0, 1024);

if( read(fd_listen, msg, 1024) == 0 )

{

printf("no clients!\n");

continue ;

}

//

 

memset(client_stat, 0, sizeof(client_stat));

sscanf(msg, "%d%s", &client_pid, client_stat);

if(strncmp("on", client_stat, 2) == 0)// client on "pid on\n"

{// pid_r.fifo(c_r - s_w)   pid_w.fifo(c_w - s_r)

printf("client: %d on\n", client_pid);

memset(fifo_name, 0, 128) ;

sprintf(fifo_name, "%d_r.fifo", client_pid);

memset(path_name, 0, 128) ;

sprintf(path_name, "%s/%s", PIPE_PATH, fifo_name);

 

pnew = (pCLIENT)calloc(1, sizeof(CLIENT));

pnew ->m_id = client_pid ;

printf("pid_r.fifo: %s\n", path_name);

pnew ->m_send = open(path_name, O_WRONLY);

printf("send_fd: %d\n", pnew ->m_send);

memset(fifo_name, 0, 128) ;

sprintf(fifo_name, "%d_w.fifo", client_pid);

memset(path_name, 0, 128) ;

sprintf(path_name, "%s/%s", PIPE_PATH, fifo_name);

 

printf("pid_w.fifo: %s\n", path_name);

pnew ->m_recv = open(path_name, O_RDONLY);

printf("recv_fd: %d\n", pnew ->m_recv);

 

printf("open client fifo: %d, %d\n", pnew ->m_send, pnew ->m_recv);

 

FD_SET(pnew ->m_recv, &rd_sets);

 

pnew ->m_next = plist ;

plist = pnew ;

 

 

 

 

}else//client off "pid off\n"

{

printf("client: %d off\n", client_pid);

ppre = NULL ;

pcur = plist ;

while(pcur && pcur ->m_id != client_pid)

{

ppre = pcur ;

pcur = pcur ->m_next ;

}

if(pcur == NULL)

{

printf("not exist!\n");

continue ;

}else

{

if(ppre == NULL)

{

plist = pcur ->m_next ;

}else

{

ppre ->m_next = pcur ->m_next ;

}

close(pcur ->m_send) ;

close(pcur ->m_recv) ;

 

FD_CLR(pcur ->m_recv, &rd_sets);

 

free(pcur);

printf("clear ok !\n");

 

}

}

}

 

 

pcur = plist ;

while(pcur)

{

if(FD_ISSET(pcur ->m_recv, &bak_sets))// translate

{

memset(msg, 0, 1024);

read(pcur -> m_recv, msg, 1024);

 

dispatch_msg(plist, msg);

}

pcur = pcur ->m_next ;

}

 

}

 

return 0 ;

}

 

 

 

 

3、用戶client.c

/*************************************************************************

> File Name: client.c

> Author: Comst

> Mail:[email protected] 

> Created Time: Sun 01 Feb 2015 06:04:36 PM CST

 ************************************************************************/

#include<stdio.h>

#include<stdlib.h>

#include<string.h>

#include<unistd.h>

#include<sys/stat.h>

#include<sys/types.h>

#include<fcntl.h>

#include<sys/select.h>

#include<sys/time.h>

#define PIPE_PATH "/home/comst/pipe"

#define PIPE_NAME "server.fifo"

int main(int argc, char* argv[])

{

int fd_server ;

char path_name[128]="";

char fifo_name[128] ;

char msg[1024] ="" ;

int fd_recv, fd_send ;

sprintf(path_name, "%s/%s", PIPE_PATH, PIPE_NAME);

 

fd_server = open(path_name, O_WRONLY);

if(fd_server == -1)

{

printf("open fail!\n");

exit(1) ;

}

// pid_r.fifo pid_w.fifo

//

memset(fifo_name, 0, 128);

sprintf(fifo_name, "%u_r.fifo", getpid());

memset(path_name, 0, sizeof(path_name));

sprintf(path_name, "%s/%s", PIPE_PATH, fifo_name);

if(-1 == mkfifo(path_name, 0666) )

{

printf("mkfif fail: %s\n", path_name);

exit(1) ;

}

 

printf("%s open\n", path_name);

 

memset(fifo_name, 0, 128);

sprintf(fifo_name, "%u_w.fifo", getpid());

memset(path_name, 0, sizeof(path_name));

sprintf(path_name, "%s/%s", PIPE_PATH, fifo_name);

if(mkfifo(path_name, 0666) == -1 )

{

printf("mkfif fail: %s\n", path_name);

exit(1) ;

}

printf("%s open\n", path_name);

 

printf("mkfifo over!\n");

 

sprintf(msg, "%u on\n", getpid());

printf("msg: %s\n", msg);

 

write(fd_server, msg, strlen(msg));

 

memset(fifo_name, 0,  128);

sprintf(fifo_name, "%u_r.fifo", getpid());

memset(path_name, 0, sizeof(path_name));

sprintf(path_name, "%s/%s", PIPE_PATH, fifo_name);

 

fd_recv = open(path_name, O_RDONLY);

 

memset(fifo_name, 0,  128);

sprintf(fifo_name, "%u_w.fifo", getpid());

memset(path_name, 0, sizeof(path_name));

sprintf(path_name, "%s/%s", PIPE_PATH, fifo_name);

 

fd_send = open(path_name, O_WRONLY);

 

printf("fifo open %d %d\n", fd_send, fd_recv);

 

fd_set rd_sets ;

FD_ZERO(&rd_sets);

while(1)

{

FD_SET(0, &rd_sets);

FD_SET(fd_recv, &rd_sets);

 

select(1024, &rd_sets, NULL, NULL, NULL);

 

if(FD_ISSET(0, &rd_sets))

{

memset(msg, 0, sizeof(msg)) ;

sprintf(msg, "from %u: ", getpid());

read(0, msg + strlen(msg),  1024 - strlen(msg) );

write(fd_send, msg, strlen(msg));

 

}

if(FD_ISSET(fd_recv, &rd_sets))

{

memset(msg, 0, sizeof(msg)) ;

read(fd_recv, msg, 1024);

write(1, msg, strlen(msg));

}

 

 

}

 

}

 

 

4、轉發函數func.c

 

/*************************************************************************

> File Name: ./func.c

> Author: Comst

> Mail:[email protected] 

> Created Time: Sun 01 Feb 2015 05:57:36 PM CST

 ************************************************************************/

 

#include"my_server.h"

void dispatch_msg(pCLIENT phead, char* msg)

{

while(phead)

{

write(phead ->m_send, msg, strlen(msg));

phead = phead ->m_next ;

}

}

 

注:宏定義   #define PIPE_PATH "/home/comst/pipe"  在不同的文件系統中路徑不同,讀者應根據具體情況定義。

 

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