#include <sys/types.h>
#include <sys/msg.h>
#include <sys/ipc.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>
#include "msg.h"
/*
char recv[10];//字符数组存储接收到的消息
int i = 0;//计数
*/
//用于存储登录用户的进程号
typedef struct LinkNode{
int data;
struct LinkNode *next;
}ListNode,*LinkList;
//函数声明
void BroadCast(LinkList head,int msgid,struct msgbuf *msg);
LinkList CreateLinkList(); //创建链表
int length(LinkList head); //获取链表的长度
int Empty(LinkList head); //判断链表是否为空
int Insert(LinkList head,int value); //往链表中录入进程号
void Delete(LinkList head,int value);
void getFilter(struct msgbuf *msg); //过滤器
void replace(char *str1,char *str2,char *str3);
int main()
{
int server_sockfd;//服务器端套接字
int client_sockfd;//客户端套接字
int len;
struct sockaddr_in my_addr; //服务器网络地址结构体
struct sockaddr_in remote_addr; //客户端网络地址结构体
int sin_size;
char buf[BUFSIZ]; //数据传送的缓冲区
memset(&my_addr,0,sizeof(my_addr)); //数据初始化--清零
my_addr.sin_family=AF_INET; //设置为IP通信
my_addr.sin_addr.s_addr=INADDR_ANY;//服务器IP地址
my_addr.sin_port=htons(8000); //服务器端口号
key_t key;
pid_t pid;
int msgid; //保存消息队列标志号
char buf[MSG_SIZE];
char *p;
if((key = ftok("./",'s'))==-1){
perror("ftok error.");
exit(1);
}
//创建或获取已有KEY消息队列
if((msgid = msgget(key,IPC_CREAT|MSG_Q_PERM))==-1){
perror("msgget error.");
exit(1);
}
//使用fork创建子进程,用来实现消息的转发
if((pid = fork())==-1){
exit(1);
}else if(pid == 0){ //pid=0,当前进程为子进程
//创建单链表,用于保存消息
LinkList head;
head = CreateLinkList();
while(1){
//从消息队列中获取一条消息
if(msgrcv(msgid,&msg,MSG_LEN,MSG_TO_SERVER,0)==-1){
perror("msgrcv error.\n");
exit(1);
}else{
//过滤消息敏感词
getFilter(&msg);
//对接收到的消息,子进程进行消息类型判断
switch(msg.subtype)
{
case 1: //客户端登录
if(Insert(head,msg.pid)!=0){
printf("insert error.\n");
exit(1);
}
printf("[Name: -%s- Login]\n",msg.user_name);
BroadCast(head,msgid,&msg); //把收到的消息广播
break;
case 2: //消息广播
BroadCast(head,msgid,&msg);
if(strncmp(msg.mtext,"quit",4)==0){
exit(0);
}
break;
case 3: //客户端退出
if(!Empty(head)){
Delete(head,msg.mtype);
}
printf("[Name: -%s- Logout]\n",msg.user_name);
BroadCast(head,msgid,&msg);
break;
default:
break;
}
}
}
}else{//父进程用于服务器控制台
msg.mtype = MSG_TO_SERVER;
msg.subtype = 2;
while(1){
printf("[server console]\n");
fgets(msg.mtext,MSG_SIZE,stdin);
//收到quit时,server关闭
if(strncmp(msg.mtext,"quit",4)==0){
msgsnd(msgid,&msg,MSG_LEN,0);
sleep(2);
msgctl(msgid,IPC_RMID,NULL); //删除消息队列
kill(pid,SIGKILL); //杀死子进程
exit(0);
}
/*
recv[i] = msg.mtext; //将来自于不同玩家的消息存入数组
i++;
}
int num[10];
int t;
for(int j=0;i<i;j++) //char转int
{
num[j] = atoi(recv[j]);
}
for (int k = 0; k < i; k++) //排序
{
for (int j = 0; j < k; j++)
if (num[j] > num[j+1])
{
temp = num[j];
num[j] = num[j+1];
num[j+1] = temp;
}
}
for(int l=0;l<i;l++) //输出最终结果
{
printf("%d",num[l]);
}
*/
}
}
return 0;
}
LinkList CreateLinkList()
{
LinkList head;
head = (LinkList)malloc(sizeof(ListNode));
head->next = NULL;
return head;
}
void BroadCast(LinkList head,int msgid,struct msgbuf *msg)
{
int i;
for(i=0 ;i<Length(head) ;i++){
msg->mtype = GetValue(head,i);
if(msg->mtype != msg->pid){//mtype = pid说明是发送消息的客户端,不用再接收自己发送的消息
msgsnd(msgid,msg,MSG_LEN,0);
}
}
}
int Length(LinkList head)
{
int n = 0;
head = head->next;
while(head){
n++;
head = head->next;
}
return n;
}
int Empty(LinkList head)
{
return (head->next == NULL);
}
int Insert(LinkList head,int value)
{
LinkList p;
p = (LinkList)malloc(sizeof(ListNode));
p->data = value;
p->next = NULL;
while(head->next){
head = head->next;
}
head->next = p;
return 0;
}
void Delete(LinkList head,int value)
{
LinkList p = head->next;
while(p!=NULL){
if(p->data == value){
head->next = p->next;
free(p);
p = head->next;
}else{
head = p;
p = p->next;
}
}
}
//pos为数据的索引值
int GetValue(LinkList head,int pos)
{
head = head->next;
while(pos--){
head = head->next;
}
return head->data;
}
//过滤器
void getFilter(struct msgbuf *msg)
{
FILE *fp;
char stu[10];
char buf[]="**";
fp = fopen("list.txt","r+");
if(fp == NULL){
perror("open list.txt failed\n");
exit(1);
}
fseek(fp,0,SEEK_SET);
while(!feof(fp)){
fgets(stu,sizeof(stu),fp);
replace(msg->mtext,stu,buf);
}
fclose(fp);
}
//将str1出现的所有的str2都替换为str3
void replace(char *str1,char *str2,char *str3){
char str4[strlen(str1)+1];
char *p;
while(strstr(str1,str2)!=NULL){
strcpy(str4,str1);
if((p=strstr(str1,str2))!=NULL){
//将str1指针移动到p的位置
while(str1!=p&&str1!=NULL){
str1++;
}
str1[0]='\0';
strcat(str1,str3);
strcat(str1,strstr(str4,str2)+strlen(str2));
}
}
}