//server.c
#include "Packet.h"
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <stdlib.h>
#include <fcntl.h>
void sys_err(char *str, int exitno)
{
perror(str);
exit(exitno);
}
int find(char *Name, char LoginList[100][5], int LoginNum)
{
int i = 0;
for (; i < LoginNum; ++i)
{
if (strcmp(LoginList[i], Name) == 0)
{
return i;
}
}
return -1;
}
void send(const Packet *packet)
{
int fd;
fd = open(packet->dest, O_RDWR);
printf("%s send\n", packet->dest);
if (fd < 0)
{
sys_err("send", 1);
}
if (write(fd, packet, sizeof(Packet)) < 0)
{
sys_err("write", 1);
}
}
void recv(int fd)
{
Packet packet;
int len, LoginNum = 0, i, res;
char LoginList[100][5];
while (1)
{
len = read(fd, &packet, sizeof(Packet));
//大于0 说明读取成功
if (len > 0)
{
switch(packet.id)
{
//一号为登录包
case 1:
strcpy(LoginList[LoginNum++], packet.src);
if (mkfifo(packet.src, 0777) > 0)
{
sys_err(packet.src, 3);
}
printf("%s Login\n", packet.src);
break;
//二号为聊天包
case 2:
if (find(packet.dest, LoginList, LoginNum) == -1)
{
Packet temp;
temp.id = 3;
strcpy(temp.src,"ser");
strcpy(temp.dest, packet.src);
sprintf(temp.data, "%s is not online", packet.dest);
send(&temp);
}
send(&packet);
break;
//三号为退出包
case 3:
res = find(packet.src, LoginList, LoginNum);
if (res >= 0)
{
LoginNum--;
for (i = res; i < LoginNum; ++i)
{
strcpy(LoginList[i], LoginList[i+1]);
}
printf("%s Logout\n", packet.src);
}
break;
}
}
}
}
int main()
{
int fd;
if (mkfifo("serverfifo", 0666) > 0)
{
sys_err("mkfifo", 1);
}
fd = open("serverfifo", O_RDWR);
if (fd < 0)
{
sys_err("open", 2);
}
recv(fd);
close(fd);
return 0;
}
//Packet.h
typedef struct
{
int id;
char src[5];
char dest[5];
char data[100];
}Packet;
//Client.c
#include "Packet.h"
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <stdlib.h>
#include <fcntl.h>
void sys_err(char *str, int exitno)
{
perror(str);
exit(exitno);
}
//登录
int Login(int fd, char *LoginName)
{
Packet packet;
packet.id = 1;
strcpy(packet.src, LoginName);
strcpy(packet.dest, "server");
strcpy(packet.data, "Login");
if (write(fd, &packet, sizeof(Packet)) < 0)
{
sys_err("Login", 1);
}
return 0;
}
//退出
void Logout(int fd, char *LoginName)
{
Packet packet;
packet.id = 3;
strcpy(packet.src, LoginName);
strcpy(packet.dest, "0");
sprintf(packet.data, "%s Logout\n", LoginName);
if (write(fd, &packet, sizeof(Packet)) < 0)
{
sys_err("Logout", 1);
}
exit(1);
}
//从标准输入读取要发送的内容 发送到公用管道
void send(int fd, char *LoginName)
{
Packet packet;
char buf[105] = {0};
int len;
len = read(STDIN_FILENO, buf, 105);
if (len < 0)
{
if (errno == EAGAIN)
{
return;
}
}
else
{
//如果等于exit则退出
if (strncmp(buf, "exit", 4) == 0)
{
Logout(fd, LoginName);
}
//要发送的内容 格式为: xxxx:data
packet.id = 2;
strcpy(packet.src, LoginName);
strncpy(packet.dest, buf, 4);
strncpy(packet.data, buf+5, 100);
if (write(fd, &packet, sizeof(Packet)) < 0)
{
sys_err("send failed", 1);
}
}
}
//从私有管道中接收服务器传来的信息
void recv(int fd)
{
Packet packet;
int len;
len = read(fd, &packet, sizeof(Packet));
if (len < 0)
{
if (errno == EAGAIN)
{
return;
}
}
else
{
printf("%s:%s", packet.dest, packet.data);
}
}
void work(int fd, char *LoginName)
{
int myfd, flags, readfd;
//等待打开自己的私有管道
while (1)
{
myfd = open(LoginName, O_RDWR);
if (myfd > 0)
{
break;
}
}
//设置标准输入为非阻塞
flags = fcntl(STDIN_FILENO, F_GETFL);
flags |= O_NONBLOCK;
fcntl(STDIN_FILENO, F_SETFL, flags);
//将FIFO管道设置为非阻塞
flags = fcntl(myfd, F_GETFL);
flags |= O_NONBLOCK;
fcntl(myfd, F_SETFL, flags);
while (1)
{
send(fd, LoginName);
recv(myfd);
}
}
int main(int argc, char *argv[])
{
if (argc < 2)
{
printf("Client LoginName\n");
exit(1);
}
int fd;
fd = open("serverfifo", O_RDWR);
if (fd < 0)
{
sys_err("open", 1);
}
Login(fd, argv[1]);
work(fd, argv[1]);
close(fd);
return 0;
}
利用管道来简单的实现了一下本地聊天室,可以进一步的扩充将服务器端设置为守护进程。