//client.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <signal.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
#define MAXLEN 1024
/*消息类型*/
struct message
{
char flag[15];
char name[10];
int size;
char msg[MAXLEN];
};
struct msq
{
long msg_type;
char msg_text[5];
};
int qid=-1,fd=-1,sockfd,savefilefd=-1;
char filefromname[10];
void handleQuit(int signal_no)
{
if(fd>0) close(fd);
close(sockfd);
if(qid>0)
{
if((msgctl(qid,IPC_RMID,NULL))<0) //删除消息队列
{
printf("消息队列无法关闭\n");
exit(1);
}
}
close(savefilefd);
printf("程序正常退出\n");
raise(SIGQUIT);
}
/*******************************************************************
*功能:切割字符串
*参数:c为分隔符,left为分割后存放左边字符串,right为分隔后存放右边字符串
******************************************************************/
void cutStr(char str[],char left[], int n, char right[],int m, char c)
{
int i,k,j;
for(i = 0 ; i < n ;i++)
{
if(str[i] == c)
break;
}
if(i == n)
{
i = -1;
}
else
{
memset(left,0,strlen(left));
for(k = 0 ; k < i ; k++)
{
left[k] = str[k];
}
}
for(j = i+1 ; j < m;j++)
{
if(str[j] == '\0')
break;
right[j-i-1] = str[j];
}
left[i] = '\0';
if(j < m)
right[j-i-1] = '\0';
else
right[m] = '\0';
}
struct msq msg;
time_t timep;
void handlerecvmsg(int *sockfd)
{
int connfd = *sockfd;
int nread;
char buf[1024];
char str[1024];
struct message recvmsg;
// time_t timep;
//struct msq msg;
if(( fd =open("chatlog.txt",O_RDWR|O_APPEND))< 0)
{
perror("打开聊天记录文件失败!");
exit(1);
}
if((qid = msgget(2222,IPC_CREAT|0666)) == -1)
{
printf("创建消息队列失败\n");
exit(1);
}
msg.msg_type = getpid();
strcpy(msg.msg_text,"OK");
while(1)
{
nread = recv(connfd,&recvmsg,sizeof(struct message),0);
if(nread == 0)
{
printf("与服务器断开了连接\n");
close(fd);
close(connfd);
exit(0);
}
else if (strcmp(recvmsg.flag,"all") == 0) //客户发给所有人
{
time (&timep);
sprintf(str,"%s%s发给所有人:%s\n\n",ctime(&timep),recvmsg.name,recvmsg.msg);
}
else if (strcmp(recvmsg.flag,"view") == 0) //查看所有在线用户
{
time (&timep);
printf("%s当前在线客户端:\n%s\n\n",ctime(&timep),recvmsg.msg);
continue;
}
else //私聊
{
time (&timep);
sprintf(str,"%s%s发来的私聊消息:%s\n\n",ctime(&timep),recvmsg.name,recvmsg.msg);
}
write(fd,str,strlen(str)); //写文件,保存消息记录
//printf("%s",msg);
msgsnd(qid,&msg,sizeof(struct msq),0);
}
}
int main(int argc,char *argv[])
{
struct sockaddr_in server_addr;
int port;
int do_number;
struct message a;
char str[MAXLEN];
char buf[MAXLEN];
pthread_t pid;
if(argc != 3)
{
printf("请输入服务器IP和端口\n");
exit(1);
}
port = atoi(argv[2]);
if((sockfd =
socket(AF_INET,SOCK_STREAM,0)) == -1)
{
printf("创建socket失败\n");
exit(1);
}
signal(SIGINT,handleQuit);
printf("----------------------------------\n");
printf("||\n");
printf("| input a number to work |\n");
printf("|\t1.login\t\t\t |\n");
printf("|\t2.register\t\t |\n");
printf("|\t3.exit\t\t\t |\n");
printf("||\n");
printf("----------------------------------\n");
scanf("%d",&do_number);
gets(str);
while(do_number != 1 && do_number != 2 && do_number != 3)
{
printf("你输入的不是上面的选项,请重新输入:\n");
scanf("%d",&do_number);
gets(str);
}
if(do_number==3)
{
close(sockfd);
printf("程序已退出!\n");
exit(0);
}
bzero(&server_addr,sizeof(struct sockaddr_in));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr(argv[1]);
server_addr.sin_port = htons(port);
if(connect(sockfd,(struct sockaddr*)&server_addr,sizeof(struct sockaddr)) == -1)
{
printf("与服务器无响应,请隔一段时间再连接\n");
exit(2);
}
if(do_number ==1) //登陆
{
int n = 3;
while(n)
{
printf("请输入你的用户名:\n");
scanf("%s",a.name);
printf("请输入密码:\n");
scanf("%s",a.msg);
strcpy(a.flag,"login");
//a.flag[3] = '\0';
send(sockfd,&a,sizeof(a),0);
printf("正在等待服务器应答...\n");
recv(sockfd,buf,MAXLEN,0);
printf("接到服务器发来的信息:%s\n",buf);
if(strcmp(buf,"登录成功!") == 0)
{
//int i,j,k;
pthread_create(&pid,NULL,(void*)handlerecvmsg,(void *)&sockfd); //创建线程来处理接收的消息
gets(str);
strcpy(a.flag,"all");
while(1)
{
memset(a.msg,0,strlen(a.msg));
memset(str,0,strlen(str));
gets(str);
strcpy(buf,a.flag);
cutStr(str,a.flag,15,a.msg,MAXLEN,'$');
printf("标志信息为:%s\n",a.flag);
if(strcmp(a.flag,"view") == 0)
{
send(sockfd,&a,sizeof(a),0);
strcpy(a.flag,buf);
continue;
}
else
{
send(sockfd,&a,sizeof(a),0);
time (&timep);
sprintf(str,"%s我发给%s的私聊消息:%s\n\n",ctime(&timep),a.flag,a.msg);
write(fd,str,strlen(str));
msgsnd(qid,&msg,sizeof(struct msq),0);
continue;
}
}
}
else
{
n--;
printf("您还有%d次机会,之后将退出程序!\n",n);
}
}
close(sockfd);
exit(3);
}
else if(do_number ==2) //注册
{
int i =1 ;
char username[10];
char password[20];
char password_t[20];
char temp[20];
printf("请输入你的用户名:\n");
scanf("%s",username);
while(i)
{
printf("请输入密码:\n");
scanf("%s",password);
printf("youpass : %s\n",password);
printf("请再次输入密码:\n");
scanf("%s",password_t);
printf("passyou : %s\n",password_t);
if(strcmp(password,password_t) != 0)
{
printf("输入的密码不一样\n");
i = 1;
}
else
{
i = 0;
}
}
strcpy(a.name,username);
strcpy(a.msg,password);
strcpy(a.flag,"reg");
//a.flag[3] = '\0';
send(sockfd,&a,sizeof(a),0);
printf("正在等待服务器应答...\n");
recv(sockfd,buf,MAXLEN,0);
printf("接到服务器发来的信息:%s\n",buf);
}
close(sockfd);
return 0;
}
//display.c
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/msg.h>
#include <sys/ipc.h>
#include <sys/types.h>
int qid,fd;
struct msq
{
long msg_type;
char msg_text[5];
};
void handlequit(int sign_no)
{
close(fd);
if((msgctl(qid,IPC_RMID,NULL)) < 0)
{
printf("消息队列无法关闭\n");
exit(1);
}
printf("程序正常退出\n");
raise(SIGQUIT);
}
int main()
{
char buf[1024];
int n;
struct msq msg;
fd = open("chatlog.txt",O_RDONLY|O_CREAT);
signal(SIGINT,handlequit);
if(fd<0)
{
printf("打开文件失败\n");
return -1;
}
lseek(fd,0,SEEK_END);
if((qid = msgget(2222,IPC_CREAT|0666)) == -1)
{
printf("创建消息队列失败\n");
close(fd);
return -1;
}
while(1)
{
if(msgrcv(qid,&msg,sizeof(msg),0,0) < 0)
{
printf("读取消息对列失败\n客户端可能已经退出本程序将一起退出\n");
close(fd);
return -1;
}
memset(buf,0,sizeof(buf));
n = read(fd,buf,1024);
write(STDOUT_FILENO,buf,n);
}
close(fd);
return 0;
}
//check.c
#include "check.h"
int reg_check(struct message *recievemsg)
{
int fd;
int read_size,write_size;
struct message cmpmsg;
if(strlen(recievemsg->name)>10 ||
strlen(recievemsg->msg)>20 )
{
return 1;
}
if(strcmp(recievemsg->name,"all")==0)
{
return -1;
}
if(strcmp(recievemsg->name,"reg")==0)
{
return -1;
}
if(strcmp(recievemsg->name,"login")==0)
{
return -1;
}
if(strcmp(recievemsg->name,"trans")==0)
{
return -1;
}
if((fd=open("user.txt",O_RDWR|O_APPEND|0666))<0)
{
perror("open");
printf("open\n");
return -2;
}
do
{
if((read_size=read(fd,&cmpmsg,sizeof(cmpmsg)))< 0)
{
perror("read");
close(fd);
return -2;
}
if(read_size != sizeof(struct message) && read_size !=0)
{
close(fd);
return -2;
}
if(strcmp(recievemsg->name,cmpmsg.name)==0)
{
close(fd);
return -1;
}
}while(read_size == sizeof(struct message));
if((write_size=write(fd,recievemsg,sizeof(struct message)))<0)
{
perror("write");
close(fd);
return -2;
}
while(write_size!=sizeof(struct message))
{
//write_size = 0-writesize;
lseek(fd,-write_size,SEEK_CUR);
write_size=write(fd,recievemsg,sizeof(struct message));
}
printf("write file success\n");
close(fd);
return 0;
}
int login_check(struct message *recievemsg)
{
int fd;
struct message cmpmsg;
int read_size;
if((fd=open("user.txt",O_RDONLY))<0)
{
perror("open");
return -2;
}
do
{
if((read_size=read(fd,&cmpmsg,sizeof(struct message)))<0)
{
perror("read");
close(fd);
return -2;
}
if(read_size != sizeof(struct message) &&
read_size!=0)
{
close(fd);
return -2;
}
if((strcmp(recievemsg->name,cmpmsg.name)==0
)&&(strcmp(recievemsg->msg,cmpmsg.msg)==0))
{
close(fd);
return 0;
}
}while(read_size>0);
close(fd);
return -1;
}
//check.h
#include <fcntl.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <pthread.h>
#define MAXLEN 1024
struct message
{
char flag[15];
char name[10];
int size;
char msg[MAXLEN];
};
int reg_check(struct message *recievemsg);
int login_check(struct message *recievemsg);
//linklist.c
#include "linklist.h"
LinkList CreateLinkList()
{
LinkList L = (LinkList)malloc(sizeof(LNode));
L->next = NULL;
return L;
}
void deletelist(LinkList L ,datatype e)
{
int i=0;
LinkList s,p;
p = L;
while ( (strcmp(p->data.name,e.name) != 0) && p->next != NULL)
{
s=p;
p = p->next;
}
if (p->next == NULL &&
(strcmp(p->data.name,e.name) != 0))
{
return;
}
else
{
s->next = p->next;
free(p);
}
}
void insertend(LinkList L,datatype e)
{
int i=0;
LinkList s,p;
p = L;
while(p->next != NULL)
{
p = p->next;
i++;
}
s = (LinkList)malloc(sizeof(LNode));
s->data =e;
s->next = p->next ;
p->next =s;
}
void DisplayList(LinkList L)
{
L=L->next;
int i = 1;
while (L != NULL)
{
printf("%d. %s \n",i,L->data.name);
L = L->next;
i++;
}
}
//linklist.h
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <errno.h>
#include <netinet/in.h>
#include <pthread.h>
/*客户端信息*/
typedef struct _clientinf
{
char name[10];
struct sockaddr_in addr_in;
int decr;
pthread_t pid;
}clientinf;
typedef clientinf datatype;
/*链表节点*/
typedef struct _LNode
{
datatype data;
struct _LNode * next;
}LNode,*LinkList;
extern LinkList CreateLinkList(void);
extern void deletelist(LinkList L ,datatype e);
extern void insertend(LinkList L,datatype e);
extern void DisplayList(LinkList L);
#server:
server:server.o linklist.o check.o
gcc server.o linklist.o check.o -lpthread -o server
server.o:server.c check.h linklist.h
gcc -c server.c
check.o:check.c check.h
gcc check.c -c
clean:
rm server.o linklist.o check.o server
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <errno.h>
#include <netinet/in.h>
#include <pthread.h>
#include <arpa/inet.h>
#include <signal.h>
#include "linklist.h"
#include "check.h"
LinkList clientlink; //客户端信息链表
/****************************************************
*功能:处理信息
*****************************************************/
void handlesignal()
{
int choose;
char name[10];
while(1)
{
printf("1.T除指定客户端,2.关闭服务器,3.显示在线客户端\n");
scanf("%d",&choose);
while(choose < 1 || choose > 3)
{
printf("请输入上面提示的选项:\n");
scanf("%d",&choose);
}
gets(name);
if(choose == 1)
{
printf("请输入你踢出去的客户端名字:\n");
gets(name);
if(strcmp(name,"") == 0) continue;
LinkList L,s;
L = clientlink;
L=L->next;
s = L;
while((strcmp(L->data.name,name) != 0)
&& L->next != NULL)
{
s = L;
L = L->next;
}
//printf("1%s\n",L->data.name);
if(L->next == NULL && (strcmp(L->data.name,name) != 0))
{
printf("该客户端不存在\n");
}
else
{
close(L->data.decr); //关闭套接字
pthread_cancel(L->data.pid); //关闭对应线程
s->next = L->next;
free(L);
}
printf("3\n");
}
else if(choose == 2) return;
else if(choose == 3)
{
DisplayList(clientlink);
}
}
}
/***********************************************************
*函数功能:处理客户请求
**********************************************************/
void handleclient (clientinf *client)
{
clientinf clientNode = *client;
int nread;
struct message a;
LinkList transfileNode;
char buf[MAXLEN],str[MAXLEN];
while(1)
{
nread =recv(clientNode.decr,&a,sizeof(a),0);
if(nread == 0)
{
strcpy(a.flag,"sermsg");
printf("客户端%s退出\n",clientNode.name);
deletelist(clientlink ,clientNode);
LinkList L;
L = clientlink;
L=L->next;
sprintf(buf,"客户端%s退出\n",clientNode.name);
while(L != NULL)
{
send(L->data.decr,buf,strlen(buf)+1,0);
L = L->next;
}
return;
}
if(strcmp(a.flag,"login") == 0) //登录
{
int i;
i = login_check(&a);
if(i == 0)
{
strcpy(buf,"登录成功!");
strcpy(clientNode.name,a.name);
insertend(clientlink,clientNode);
send(clientNode.decr,buf,strlen(buf)+1,0);
}
else
{
strcpy(buf,"登录失败!");
send(clientNode.decr,buf,strlen(buf)+1,0);
}
continue;
}
else if(strcmp(a.flag,"reg") == 0) //注册
{
int i;
i = reg_check(&a);
if(i == 0)
{
strcpy(buf,"注册成功!");
strcpy(clientNode.name,a.name);
send(clientNode.decr,buf,strlen(buf)+1,0);
}
continue;
}
else if (strcmp(a.flag,"all") == 0) //给所有人发消息
{
if (strcmp(a.msg,"") != 0)
{
LinkList L;
L = clientlink;
L=L->next;
strcpy(a.name,clientNode.name);
while(L != NULL)
{
send(L->data.decr,&a,sizeof(struct message),0);
L = L->next;
}
}
continue;
}
else if(strcmp(a.flag,"view") == 0) //查看用户列表
{
LinkList L;
int i = 1;
L = clientlink;
L=L->next;
memset(buf,0,strlen(buf));
while(L != NULL)
{
memset(str,0,strlen(str));
sprintf(str,"%d. %s\n",i,L->data.name);
strcat(buf,str); //将消息合成一个消息
L = L->next;
i++;
}
strcpy(a.name,clientNode.name);
strcpy(a.msg,buf);
send(clientNode.decr,&a,sizeof(struct message),0);
continue;
}
else //私聊
{
LinkList L;
L = clientlink;
L=L->next;
strcpy(a.name,clientNode.name);
while(L != NULL)
{
if (strcmp(L->data.name,a.flag) == 0)
{
send(L->data.decr,&a,sizeof(struct message),0);
break;
}
L = L->next;
}
continue;
}
}
}
/***********************************************************
*函数功能:处理接受请求
************************************************************/
void handleaccept(int *serverfd)
{
socklen_t client_len;
int sockfd = *serverfd;
clientinf clientNode;
struct sockaddr_in client_addr;
while(1)
{
client_len =sizeof(struct sockaddr_in);
if((clientNode.decr = accept(sockfd,(struct sockaddr *)&client_addr,&client_len)) == -1)
{
printf("接收连接失败\n");
}
else
{
printf("与%s:%d连接建立成功\n",inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port));
clientNode.addr_in = client_addr;
pthread_create(&clientNode.pid,NULL,(void *)handleclient,(void *)&clientNode); //只要有连接请求,就创建线程来处理
}
}
}
int main(int argc ,char *argv[])
{
struct sockaddr_in server_addr,client_addr;
int sockfd,connectfd,port,nread;
pthread_t pid;
char buf[MAXLEN];
char str[MAXLEN];
if(argc != 2)
{
printf("请输入端口\n");
exit(1);
}
if((sockfd =
socket(AF_INET,SOCK_STREAM,0)) == -1)
{
printf("创建socket失败\n");
exit(1);
}
clientlink = CreateLinkList();
clientlink->data.decr = sockfd;
port = atoi(argv[1]);
bzero(&server_addr,sizeof(struct sockaddr_in));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr =htonl(INADDR_ANY);
server_addr.sin_port = htons(port);
if(bind(sockfd,(struct sockaddr *)&server_addr,sizeof(struct sockaddr)) == -1)
{
printf("绑定端口失败,端口可能被占用\n");
exit(2);
}
if(listen(sockfd,20) == -1)
{
printf("监听端口失败\n");
exit(3);
}
printf("正在监听中...\n");
pthread_create(&pid,NULL,(void*)handleaccept,(void *)&sockfd);
handlesignal();
return 0;
}