服务器
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <strings.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
#define LOGIN 1
#define REGISTER 2
#define QUIT 3
typedef struct data //定义结构体,保存用户信息,用于登录时检验登陆的合法性
{
char name[20];
char passwd[20];
struct data *next;
}DATA,*PDATA;
typedef struct node //定义结构体,保存在线用户信息
{
char OnlineName[20];
int sockfd;
char Msg[100];
struct node *next;
}NODE,*PNODE;
void LoadDataFromList(PDATA head) //从文本中加载用户信息
{
FILE *fp=fopen("Userlist.txt","r+");
if(NULL==fp)
{
printf("open is failed!\n");
exit(0);
}
DATA data;
while(1==fread(&data,sizeof(DATA),1,fp)) //读取按数值来读取,不可以定义指针来读取
{
PDATA temp=(PDATA)malloc(sizeof(DATA));
strcpy(temp->name,data.name);
strcpy(temp->passwd,data.passwd);
temp->next=head->next;
head->next=temp;
}
fclose(fp);
fp=NULL;
}
void SaveDataToList(PDATA head) //对于新注册的用户,记录到文本文件中
{
FILE *fp=fopen("Userlist.txt","w+");
if(fp==NULL)
{
printf("open is failed!\n");
exit(0);
}
PDATA p=head->next;
DATA data;
while(p)
{
strcpy(data.name,p->name);
strcpy(data.passwd,p->passwd);
fwrite(&data,sizeof(DATA),1,fp); //写入时,只能以数据形式写入,不能用指针链表写入
p=p->next;
}
fclose(fp);
fp=NULL;
}
void Login(int connfd,char name[])
{
int commond=-1;
char newName[20]={'\0'};
char passwd[20]={'\0'};
PDATA head = (PDATA)malloc(sizeof(DATA));
head->next=NULL;
LoadDataFromList(head);
do
{
PDATA p=head->next;
read(connfd,&commond,sizeof(int));
if(commond==LOGIN)
{
read(connfd,newName,sizeof(newName));
read(connfd,passwd,sizeof(passwd));
while(p!=NULL)
{
if(!strcmp(p->name,newName) && !strcmp(p->passwd,passwd))
{
write(connfd,"allow",20);
strcpy(name,newName);
return;
}
p=p->next;
}
write(connfd,"deny",20);
continue;
}
else if(commond==REGISTER)
{
read(connfd,newName,sizeof(newName));
read(connfd,passwd,sizeof(passwd));
while(p)
{
if(!strcmp(p->name,newName)) //判断新注册的用户和系统原用户不重名
{
write(connfd,"deny",20);
}
p=p->next;
}
PDATA q=(PDATA)malloc(sizeof(DATA));
q->next=head->next;
head->next=q;
strcpy(q->name,newName);
strcpy(q->passwd,passwd);
SaveDataToList(head);
write(connfd,"allow",20);
}
else if(commond==QUIT)
{
close(connfd);
break;
}
}while(1);
}
void *chatroom(void *arg)
{
PNODE headGroup=(PNODE) arg;
do
{
sleep(1);
PNODE t=headGroup->next;
while(t)
{
if(read(t->sockfd,t->Msg,sizeof(t->Msg))>0)
{
printf("t->Msg:%s\n",t->Msg);
char MSG[100]={'\0'};
strcat(MSG,t->OnlineName);
strcat(MSG,":");
strcat(MSG,t->Msg);
PNODE s=headGroup->next;
while(s)
{
write(s->sockfd,MSG,sizeof(MSG));
s=s->next;
}
printf("t->sockfd=%d\n",t->sockfd);
sleep(1);
}
t=t->next;
}
}while(1);
}
int main()
{
int listenfd = -1;
int connfd = -1;
int i = 0;
int j = 0;
char name[20]={'\0'};
char MsgName[100]={0};
char Div[]="/";
PNODE head=(PNODE)malloc(sizeof(NODE));
head->next=NULL;
socklen_t clilen = 0;
struct sockaddr_in cliaddr = {0};
struct sockaddr_in servaddr = {0};
int ret = 0;
listenfd = socket(AF_INET, SOCK_STREAM, 0); //开启套接口
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
inet_aton("127.0.0.1", &(servaddr.sin_addr));
servaddr.sin_port = htons(5678);
ret = bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr));
ret += listen(listenfd, 5);
while(1)
{
clilen = sizeof(cliaddr);
connfd = accept(listenfd, (struct sockaddr *) &cliaddr, &clilen);
printf("CLient Ip:%s\n",inet_ntoa(cliaddr.sin_addr));
Login(connfd,name); //这里将空名字传入,在函数里将读到的名字赋予这个指针,方便后用
printf("%s log in\n",name);
PNODE p=(PNODE)malloc(sizeof(NODE));
strcpy(p->OnlineName,name); //将登陆成功的用户名加入在线链表 中
p->sockfd=connfd;
p->next=head->next;
head->next=p;
PNODE q=head->next;
memset(MsgName,0,sizeof(MsgName));
while(q)
{
strcat(MsgName,q->OnlineName); //遍历链表,strcat函数将所有的在线用户名连在一起,用Div分隔符分隔开,传给客户端
strcat(MsgName,Div);
q=q->next;
}
write(connfd,MsgName,sizeof(MsgName));
printf("234: %s\n",MsgName);
memset(MsgName,0,sizeof(MsgName));
int test = read(connfd,MsgName,sizeof(MsgName));
printf("MsgName=%s\n",MsgName);
char *OnlineName=NULL;
OnlineName=strtok(MsgName,Div); //strtok函数将客户端传来的字符串拆开,定义了字符串是以“/”隔开的
q=head->next;
PNODE t=(PNODE)malloc(sizeof(NODE));
PNODE headGroup=(PNODE)malloc(sizeof(NODE));
headGroup->next=NULL;
while(OnlineName!=NULL)
{
while(q)
{
if(!strcmp(q->OnlineName,OnlineName))
{
t=q;
t->next=headGroup->next;
headGroup->next=t;
}
q=q->next;
}
OnlineName=strtok(NULL,Div);
}
int retpth=-1;
pthread_t thread;
retpth=pthread_create(&thread,NULL,chatroom,(void *)headGroup);
if(retpth!=0)
{
perror("pthread");
return -1;
}
}
close(listenfd);
CloseAllClientFdFromArr(arrfd,NUM_FD);
return 0;
}
客户端
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <strings.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#define LOGIN 1
#define REGISTER 2
#define QUIT 3
typedef struct data
{
char name[20];
char passwd[20];
struct data *next;
}DATA,*PDATA;
typedef struct node
{
char OnlineName[20];
int sockfd;
char Msg[100];
struct node *next;
}NODE,*PNODE;
void handler(int sig)
{
if(SIGINT ==sig) //信号:监测到ctrl+c时执行退出命令
{
printf("Thank you for use!\n");
exit(0);
}
}
void LoadData(PDATA head)
{
printf("Input your username:");
scanf("%s%*c",head->name);
system("stty -echo"); //密码隐藏:关闭显示器显示,待密码输入结束时再重新开启
printf("Input your password:");
scanf("%s%*c",head->passwd);
system("stty echo");
}
void chatroom(int sockfd)
{
char MsgName[100]={'\0'};
read(sockfd,MsgName,sizeof(MsgName));
printf("Online people are %s\n Input names to chat:",MsgName);
memset(MsgName,0,sizeof(MsgName));
scanf("%s%*c",MsgName);
int test = write(sockfd,MsgName,sizeof(MsgName));
printf("58: test = %d\n",test);
printf("Start chatting\n");
char MSG[100]={'\0'};
while(1)
{
if(scanf("%[^\n]s",MSG)>0) //[^\n]从键盘缓存区中不断读入,直到回车键
{
write(sockfd,MSG,sizeof(MSG))>0;
}
if(read(sockfd,MSG,sizeof(MSG))>0)
{
printf("%s\n",MSG);
}
sleep(1);
}
}
int main(int argc, char *argv[])
{
signal(SIGINT,handler);
int sockfd;
struct sockaddr_in servaddr;
int ret = 0;
int commond=-1;
char name[20]={'\0'};
char passwd[20]={'\0'};
char feedback[20]={'\0'};
sockfd = socket(AF_INET, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(5678);
inet_aton("127.0.0.1", &servaddr.sin_addr);
ret = connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr));
if(ret < 0)
{
perror("connect");
close(sockfd);
return 1;
}
while(1)
{
printf("Welcome to the system\n Select one to continue:\n");
printf("1.Log in\t2.Register\t3.quit\n");
scanf("%d%*c",&commond);
write(sockfd,&commond,sizeof(int));
if(commond == QUIT)
{
break;
}
PDATA head=(PDATA)malloc(sizeof(DATA));
head->next=NULL;
LoadData(head);
strcpy(name,head->name);
strcpy(passwd,head->passwd);
write(sockfd,name,sizeof(name));
write(sockfd,passwd,sizeof(passwd));
read(sockfd,feedback,20);
if(commond ==LOGIN)
{
if(!strcmp(feedback,"allow"))
{
chatroom(sockfd);
printf("========\n");
getchar();
}
else if(!strcmp(feedback,"deny"))
{
printf("Wrong username or password\n");
continue;
}
}
else if(commond==REGISTER)
{
if(!strcmp(feedback,"allow"))
{
printf("Register in\n");
}
else if(!strcmp(feedback,"deny"))
{
printf("Confict username,try again!\n");
}
continue;
}
}
close(sockfd);
return 0;
}