/*************************************************************************
> File Name: 01socket.c
> Author: ma6174
> Mail: ma6174@163.com
> Created Time: Mon 22 May 2017 05:10:00 PM CST
************************************************************************/
#include<stdio.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<string.h>
#include<stdlib.h>
#include<pthread.h>
#include<fcntl.h>
//用于保存用户连接套接字的数组
char clnt_socks[1024];
int clnt_cnt = 0;
//互斥锁初始化
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
//消息类型
enum MSGTYPE
{
REGISTER_REQ,REGISTER_OK,REGISTER_ERR,
LOGIN_REQ,LOGIN_OK,LOGIN_ERR,
SEND_ALL,
};
//用户结构体,包括名字和密码
struct USER
{
char name[20];
char passwd[20];
};
//处理客户端的线程函数
void* handle_client(void*);
//用户注册
int handle_register(char*,char*);
//用户登录
int handle_login(char*,char*);
//处理错误
void handle_error(char*);
//网络初始化
void initnetwork(unsigned short port);
//服务器转发消息给所有用户
void sendmsgtoall(char *msg,int len);
//服务器监听套接字
int sockfd;
int main(int argc,char *argv[])
{
if(argc != 2)
{
printf("Usage:%s <Port> \n",argv[0]);
return 0;
}
//网络初始化,需要命令行参数:端口号
unsigned short port = atoi(argv[1]);
initnetwork(port);
while(1)
{
int confd = accept(sockfd,NULL,NULL);
if(confd < 0)
{
perror("accept");
return -1;
}
pthread_mutex_lock(&mutex);
clnt_socks[clnt_cnt++] = confd;
pthread_mutex_unlock(&mutex);
pthread_t tid;
pthread_create(&tid,NULL,handle_client,(void*)&confd);
pthread_detach(tid);
}//end while(1)
close(sockfd);
return 0;
}
//网络初始化
void initnetwork(unsigned short port)
{
//1.
sockfd = socket(AF_INET,SOCK_STREAM,0);
if(sockfd < 0)
{
perror("socket");
exit(1);
}
//2.
struct sockaddr_in saddr;
memset(&saddr,0,sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_port = htons(port);
saddr.sin_addr.s_addr = htonl(INADDR_ANY);
//3.
int res = bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));
if(res < 0)
{
perror("bind");
exit(1);
}
printf("bind success!\n");
//4.
res = listen(sockfd,10);
if(res < 0)
{
perror("listen");
exit(1);
}
printf("init ok!!\n");
}
void* handle_client(void *arg)
{
int confd = *((int*)arg);
printf("confd = %d \n",confd);
int res;
enum MSGTYPE type;
while(1)
{
res = read(confd,&type,sizeof(type));
if(res == 0)
{
//客户断线,移除其连接套接字
int i;
pthread_mutex_lock(&mutex);
for(i = 0; i < clnt_cnt; i++)//移除断线了的客户端
{
if(confd == clnt_socks[i])
{
while( i++ < clnt_cnt-1 )
{
clnt_socks[i] = clnt_socks[i+1];
}
break;
}
}
clnt_cnt--;
pthread_mutex_unlock(&mutex);
close(confd);
printf("confd %d is exited!\n",confd);
pthread_exit(0);
}
if(type == REGISTER_REQ)
{
char username[20];
char passwd[20];
read(confd,username,sizeof(username));
read(confd,passwd,sizeof(passwd));
if(handle_register(username,passwd))
{//register ok
type = REGISTER_OK;
}
else
{//register error
type = REGISTER_ERR;
}
write(confd,&type,sizeof(type));
}//end if register
if(type == LOGIN_REQ)
{
char username[20];
char passwd[20];
read(confd,username,sizeof(username));
read(confd,passwd,sizeof(passwd));
if(handle_login(username,passwd))
{//login ok
type = LOGIN_OK;
write(confd,&type,sizeof(type));
write(confd,username,sizeof(username));
}
else
{//login error
type = LOGIN_ERR;
write(confd,&type,sizeof(type));
}
}//end if login
if(type == SEND_ALL)
{
char msg[2048] = {0};
int res = read(confd,msg,sizeof(msg));
sendmsgtoall(msg,res);
}//end if type==send_all
}//end while
return NULL;
}
void sendmsgtoall(char *msg,int len)
{
printf("msg: %s \n",msg);
int i;
enum MSGTYPE type = SEND_ALL;
pthread_mutex_lock(&mutex);
for(i = 0; i < clnt_cnt; i++)
{
write(clnt_socks[i],&type,sizeof(type));
write(clnt_socks[i],msg,len);
}
pthread_mutex_unlock(&mutex);
}
void handle_error(char*errmsg)
{
perror(errmsg);
exit(1);
}
int handle_register(char *username,char *passwd)
{
printf("register:%s %s \n",username,passwd);
int fd = open("users.dat",O_RDWR | O_CREAT,0777);
if(fd < 0)
{
handle_error("open register file");
}
struct USER user;
strcpy(user.name,username);
strcpy(user.passwd,passwd);
struct USER temp;
int res;
int is_exist = 0;//1:exist,0:not exist
while(1)
{
res = read(fd,&temp,sizeof(temp));
if(res < 0)
{
perror("read userdatafile error");
exit(1);
}
printf("read res = %d \n",res);
if(res == 0)
{
break;
}
if(strcmp(user.name,temp.name) == 0)
{
is_exist = 1;
break;
}
}
printf("exist = %d\n",is_exist);
if(is_exist)//exist
{
return 0;
}
else
{
int res = write(fd,&user,sizeof(user));
if(res < 0)
{
perror("write username&passwd");
}
printf("write res = %d\n",res);
close(fd);
return 1;
}
}
int handle_login(char *username,char *passwd)
{
int fd = open("users.dat",O_RDONLY);
if(fd < 0)
{
handle_error("open register file");
}
struct USER user;
strcpy(user.name,username);
strcpy(user.passwd,passwd);
struct USER temp;
int res;
int is_exist = 0;//1:exist,0:not exist
while(1)
{
res = read(fd,&temp,sizeof(temp));
if(res == 0)
{
break;
}
if(strcmp(temp.name,username) == 0 && strcmp(temp.passwd,passwd) == 0)
{
is_exist = 1;
break;
}
}//endl while
if(is_exist)
{
return 1;
}
else
{
return 0;
}
}