fifo实现本地简单聊天程序

最近做了一个小练习,要求如下:
1.设计协议
2.客户端只写公共管道,向服务端发信息
3.客户端只读私有管道,接收信息。
4.服务端维护用户登录列表
详细如图:
fifo实现本地简单聊天程序_第1张图片

1.server

#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);
}

2.client

#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);
}

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 to send message        #\n\
# use  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

好了,开始运行一下吧:
fifo实现本地简单聊天程序_第2张图片

你可能感兴趣的:(Linux网络编程)