fifo实现本地简单聊天程序

来源:互联网 发布:安卓简单捕鱼源码 编辑:程序博客网 时间:2024/04/30 08:51

最近做了一个小练习,要求如下:
1.设计协议
2.客户端只写公共管道,向服务端发信息
3.客户端只读私有管道,接收信息。
4.服务端维护用户登录列表
详细如图:
这里写图片描述

1.server

#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <errno.h>#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);}

2.client

#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <unistd.h>#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);}

3.协议

#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<user:message> to send message        #\n\# use <exit> to exit                              #\n\###################################################\n"#endif

4.链表

#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

好了,开始运行一下吧:
这里写图片描述

0 0