最近做了一个小练习,要求如下:
1.设计协议
2.客户端只写公共管道,向服务端发信息
3.客户端只读私有管道,接收信息。
4.服务端维护用户登录列表
详细如图:
#include
#include
#include
#include
#include
#include
#include
#include
#include "protocl.h"
#include "list.h"
int main(void)
{
int status; //判断创建公有管道是否成功
int fd; //打开公有管道的文件描述符
int n; //用以保存读到的字节数
int fd_client; //打开私有管道的文件描述符
char name[MAXLINE] = {0}; //保存客户端名
char buf[MAXLINE] = {0}; //用以存放要写入管道或终端的提示信息
PROC proc; //协议,数据量大可以用堆
struct list *ls = create_list(); //创建链表,维护登录用户名列表
if ((status = mkfifo(SER_FIFO, 0644)) < 0)
sys_err("mkfifo server");
if ((fd = open(SER_FIFO, O_RDONLY)) < 0)
sys_err("open SER_FIFO");
while(1) {
if ((n = read(fd, &proc, sizeof(PROC))) > 0) {
if (proc.id == 1) { //收到的是登录包
insert_list(ls, 0, proc.src); //插入到登录列表
sprintf(buf, "%s is login\n", proc.src);
write(STDOUT_FILENO, buf, strlen(buf));
if (mkfifo(proc.src, 0644) < 0) //为登录用户创建私有会话管道
sys_err("mkfifo client");
if ((fd_client = open(proc.src, O_WRONLY)) < 0)
sys_err("open client fifo");
/* 给客户发送1号回执包,告诉登录成功 */
memset(&proc, 0, sizeof(PROC));
proc.id = 1;
strcpy(proc.data, CONNECT);
write(fd_client, &proc, sizeof(PROC));
close(fd_client);
}
if (proc.id == 2) { //会话包,转发
if ((fd_client = open(proc.dest, O_WRONLY)) < 0) {
if (errno == 2) { //没有这个文件,用户不在线
fd_client = open(proc.src, O_WRONLY);
memset(&proc, 0, sizeof(PROC));
proc.id = 3; //向发送端回发3号包 ,提示用户不在线
strcpy(proc.data, "the user is offline\n");
write(fd_client, &proc, sizeof(PROC));
close(fd_client);
}
else {
sys_err("open fd_client");
}
}
write(fd_client, &proc, sizeof(PROC));
close(fd_client);
}
if (proc.id == 4) { //退出登录包
fd_client = open(proc.src, O_WRONLY);
// memset(&proc, 0, sizeof(PROC));
proc.id = 4;
strcpy(proc.data, "exit success\n");
write(fd_client, &proc, sizeof(PROC));
close(fd_client);
unlink(proc.src);
sprintf(buf, "%s is logout\n", proc.src);
write(STDOUT_FILENO, buf, strlen(buf));
delete_node(ls, proc.src);
traverse(ls);
if (empty_list(ls) == 0)
break;
}
}
}
free(ls);
close(fd);
unlink(SER_FIFO);
exit(0);
}
#include
#include
#include
#include
#include
#include
#include
#include "protocl.h"
int main(void)
{
int fd, fd_client; //用来保存打开公有管道和私有管道的文件描述符
int n; //保存读到的字节数
char buf[MAXLINE]; //保存一些用来写到终端上的提示信息
char name[MAXLINE]; //保存客户端用户名
PROC proc_client; //封装的协议
printf("enter your user name(1 character): ");
scanf("%s", name);
/* 设置非阻塞读标准输入 */
int flags = fcntl(STDIN_FILENO, F_GETFL, 0);
if (fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK) < 0)
sys_err("fcntl");
if ((fd = open(SER_FIFO, O_WRONLY)) < 0)
sys_err("open");
/* 登录 */
proc_client.id = 1;
strcpy(proc_client.src, name);
write(fd, &proc_client, sizeof(proc_client));
sleep(1); //保证服务端收到以后建立私有管道
if ((fd_client = open(name ,O_RDONLY | O_NONBLOCK)) < 0) //非阻塞读私有管道
sys_err("open");
while(1)
{
memset(&proc_client, 0, sizeof(PROC));
if ((n = read(fd_client, &proc_client, MAXLINE)) > 0)
{
if (proc_client.id == 1 || proc_client.id == 3) {
write(STDOUT_FILENO, proc_client.data, strlen(proc_client.data));
}
if (proc_client.id == 2) {
memset(buf, 0, MAXLINE);
sprintf(buf, "%s:%s", proc_client.src, proc_client.data);
write(STDOUT_FILENO, buf, strlen(buf));
memset(buf, 0, MAXLINE);
}
if (proc_client.id == 4) {
write(STDOUT_FILENO, proc_client.data, strlen(proc_client.data));
break;
}
}
if ((n = read(STDIN_FILENO, buf, MAXLINE)) > 0) {
if (strncmp(buf, "exit", 4) == 0)
{
proc_client.id = 4;
strcpy(proc_client.src, name);
write(fd, &proc_client, sizeof(PROC));
}
else /* send message */
{
memset(&proc_client, 0, sizeof(PROC));
proc_client.id = 2;
strcpy(proc_client.src, name);
strncpy(proc_client.dest, buf, 1);
strcpy(proc_client.data, buf+2);
write(fd, &proc_client, sizeof(PROC));
memset(buf, 0, MAXLINE);
}
}
sleep(1);
}
close(fd);
close(fd_client);
exit(0);
}
#ifndef __PROTOCL__
#define __PROTOCL__
typedef struct _PROTOCL
{
int id;
char src[4];
char dest[4];
char data[1024];
}PROC;
void sys_err(char *);
#define MAXLINE 1024
#define SER_FIFO "SER_FIFO"
#define CONNECT "\
###################################################\n\
# you have connect with the server successfully! #\n\
# use format to send message #\n\
# use to exit #\n\
###################################################\n"
#endif
#ifndef __LIST_H__
#define __LIST_H__
struct list
{
char name[4];
struct list *next;
};
struct list *create_list();
void traverse(struct list *ls);
struct list *insert_list(struct list *ls, int n, char *str);
int delete_node(struct list *ls, char *str);
int empty_list(struct list *ls);
#endif