客户端实现了判单用户登录结果、防止单回车字符发送、保存和显示历史聊天记录(仅自己)、退出聊天室功能。
服务端实现了验证用户是否已经存在(支持最大64用户连接)支持广播用户进入退出聊天室以及用户聊天内容。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
typedef struct sockaddr SA;
typedef struct sockaddr_in SIN;
#define MAXBACKLOG 100
int Socket(int domain,int type,int protocol);
int Connect(int sockfd,struct sockaddr * serv_addr,int addrlen);
void *son_fun(void * arg);
void save(const char * dbuff,const char * nbuff);
void list_history_msg(const char * nbuff);
int main(int argc,char *argv[])
{
char namebuff[512]={0};
pthread_t id;
//建立监听套接字
int socketfd = Socket(AF_INET,SOCK_STREAM,0);
//connect
SIN serverinfo;
serverinfo.sin_family = AF_INET;
serverinfo.sin_port = htons(atoi(argv[2]));
serverinfo.sin_addr.s_addr = inet_addr(argv[1]);
int addrlen = sizeof(SIN);
Connect(socketfd,(SA*)&serverinfo,addrlen);
//send name
printf("请输入昵称:\n");
gets(namebuff);
write(socketfd,namebuff,sizeof(namebuff));
char b[20];
read(socketfd,b,sizeof(b));
if(strstr(b,"已存在"))
{
printf("已存在\n");
close(socketfd);
return 0;
}
//print serve info
printf("登入成功,服务器:%s 端口:%d\n",inet_ntoa(serverinfo.sin_addr),ntohs(serverinfo.sin_port));
//make son thread
pthread_create(&id,NULL,son_fun,(void *)&socketfd);
//w
while(1)
{
//time
time_t t = time(NULL);
struct tm *tinfo = localtime(&t);
//msg
char readbuff[512] = {0};
gets(readbuff);
//prevent "\n" send to serve and save to data
if(strlen(readbuff)==0) continue;
//determine wheather it is "ls"
if(strcmp(readbuff,"ls") == 0)
{
list_history_msg(namebuff);
continue;
}
//determine wheather it is "quit"
if(strcmp(readbuff,"quit") == 0)
{
char sendbuff[618] = {0};
sprintf(sendbuff,"%s : %s%s",namebuff,asctime(tinfo),"退出聊天");
write(socketfd,sendbuff,sizeof(sendbuff));
close(socketfd);
exit(0);
}
//send
char sendbuff[618] = {0};
sprintf(sendbuff,"%s : %s%s",namebuff,asctime(tinfo),readbuff);
write(socketfd,sendbuff,sizeof(sendbuff));
//save data
save(sendbuff,namebuff);
}
//关闭
close(socketfd);
return 0;
}
void list_history_msg(const char * nbuff)
{
char path[128];
char *line = NULL;
size_t len = 0;
sprintf(path,"./userdata/%s.txt",nbuff);
FILE * fp = fopen(path,"a+");
printf("********聊天记录*********\n");
while(getline(&line , &len , fp) != -1)
printf("%s",line);
printf("************************\n");
free(line);
fclose(fp);
}
void save(const char * dbuff,const char * nbuff)
{
char path[128];
sprintf(path,"./userdata/%s.txt",nbuff);
FILE * fp = fopen(path,"a+");
fprintf(fp,"%s\n",dbuff);
fclose(fp);
}
int Socket(int domain,int type,int protocol)
{
int socketFd = socket(domain,type,protocol);
if(socketFd == -1)
{
perror("socket");
exit(1);
}
return socketFd;
}
int Connect (int sockfd,struct sockaddr * serv_addr,int addrlen)
{
int val = connect(sockfd,serv_addr,addrlen);
if(val == -1)
{
perror("connect");
exit(1);
}
return 0;
}
void *son_fun(void * arg)
{
int readpipefd = *((int *)arg);
char readbuff[512]={0};
while(1)
{
memset(readbuff,0,sizeof(readbuff));
if(read(readpipefd,readbuff,sizeof(readbuff))>0)
{
printf("%s\n\n",readbuff);
}
else
{
close(readpipefd);
pthread_exit(NULL);
}
}
}
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
typedef struct sockaddr SA;
typedef struct sockaddr_in SIN;
#define MAXBACKLOG 100
int Socket(int domain,int type,int protocol);
int Bind(int sockfd,struct sockaddr * my_addr,int addrlen);
int Listen(int s,int backlog);
int Accept(int s,struct sockaddr * addr,int * addrlen);
void *son_fun(void * arg);
int is_exist(char * username);
void broadcast(char *r,char *n);
char Userlist[64][20] = {0};
int Userfdlist[64] = {0};
int main(int argc,char *argv[])
{
//建立监听套接字
int socketfd = Socket(AF_INET,SOCK_STREAM,0);
//需要进行重用地址及其端口号
int opt = 1;
setsockopt(socketfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
//绑定信息编写服务器信息
SIN serverinfo;
serverinfo.sin_family = AF_INET; //协议IPV4
serverinfo.sin_port = htons(atoi(argv[2])); //网络字节序(大端字节序)与主机字节序(小端字节序)
serverinfo.sin_addr.s_addr = inet_addr(argv[1]);
int addrlen = sizeof(SIN);
Bind(socketfd,(SA*)&serverinfo,addrlen);
//监听
Listen(socketfd,MAXBACKLOG);
//读写
while(1)
{
//等待连接
SIN clientinfo;
int clientaddrlen = sizeof(SA);
int newfd = Accept(socketfd,(SA*)&clientinfo,&clientaddrlen);
printf("客户端地址:%s 端口号:%d\n",inet_ntoa(clientinfo.sin_addr),ntohs(clientinfo.sin_port));
//创建子线程
pthread_t id;
pthread_create(&id,NULL,son_fun,(void *)&newfd);
}
//关闭
close(socketfd);
return 0;
}
int is_exist(char * username)
{
for(int i = 0 ; i < 10; i++)
{
if(strcmp(username,Userlist[i]) == 0)
return 1;
}
return 0;
}
void *son_fun(void * arg)
{
int readfd = *((int *)arg);
char readbuff[512] = {0};
char namebuff[ 20] = {0};
read(readfd,namebuff,sizeof(namebuff));
//determine wherther it is exist
if(is_exist(namebuff))
{write(readfd,"已存在",sizeof("已存在"));close(readfd);pthread_exit(NULL);}
else
{
write(readfd,"登录成功",sizeof("登录成功"));
char r[50];
sprintf(r,"%s %s",namebuff,"进入聊天室");
printf("%s\n",r);
broadcast(r,namebuff);
}
//save username and userfd
for(int i=0;i<10;i++)
{
if(strlen(Userlist[i])==0)
{
strcpy(Userlist[i],namebuff);
Userfdlist[i] = readfd;
break;
}
}
while(1)
{
memset(readbuff,0,sizeof(readbuff));
if(read(readfd,readbuff,sizeof(readbuff))>0)
{
if(strlen(readbuff)>0)
{
//printf("%s\n\n",readbuff);
//broadcast
broadcast(readbuff,namebuff);
if(strstr(readbuff,"退出聊天"))
for(int i=0;i<10;i++)
if(strcmp(Userlist[i],namebuff)==0)
{
printf("%s\n",readbuff);
strcpy(Userlist[i],"\0");
close(readfd);
pthread_exit(NULL);
}
}
}
else
{
close(readfd);
pthread_exit(NULL);
}
}
}
void broadcast(char *r,char *n)
{
for(int i=0 ; i<10 ;i++)
//if it is a user and not himself
if(strcmp(Userlist[i],n)!=0 && strlen(Userlist[i])!=0)
write(Userfdlist[i],r,strlen(r));
}
int Socket(int domain,int type,int protocol)
{
int socketFd = socket(domain,type,protocol);
if(socketFd ==-1)
{
perror("socket");
exit(1);
}
return socketFd;
}
int Bind(int sockfd,struct sockaddr * my_addr,int addrlen)
{
int val = bind(sockfd,my_addr,addrlen);
if(val)
{
perror("bind");
exit(1);
}
return 0;
}
int Listen(int s,int backlog)
{
int val = listen(s,backlog);
if(val == -1)
{
perror("listen");
exit(1);
}
return val;
}
int Accept(int s,struct sockaddr * addr,int * addrlen)
{
int NEWfd = accept(s,addr,addrlen);
if(NEWfd == -1)
{
perror("listen");
exit(1);
}
return NEWfd;
}