/*client.c*/
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <netdb.h>
#include <netinet/in.h>
#include<malloc.h>
//#include<curses.h>//linux图形化编程界面函数
#define PORT 4321
#define BUFFER_SIZE 1024
typedef struct user
{
struct sockaddr_in users_sockaddr;//用户IP
int user_fd;//用户连接套接字
char *user_name;//用户别名
char buf[BUFFER_SIZE];//用户发的信息
char del[4];//删除下线用户信号标志位
int rece_id;
struct user *Next;
}USER_List,*pUSER_List;
pUSER_List craet_USER_listhead()
{
pUSER_List pHead=(pUSER_List)malloc(sizeof(USER_List));
if(pHead==NULL)
{
printf("The Dynamic memory allocation is fail\n");
exit(-1);
}
pHead->Next=NULL;
return pHead;
}
pUSER_List craet_USER_buff()
{
pUSER_List pbuff=(pUSER_List)malloc(sizeof(USER_List));
if(pbuff==NULL)
{
printf("The Dynamic memory allocation is fail\n");
exit(-1);
}
return pbuff;
}
pUSER_List insert_USERList(pUSER_List p,struct sockaddr_in uaddr,int fd,char *name)
{
int i=0;
pUSER_List pNew=(pUSER_List)malloc(sizeof(USER_List));
if(pNew==NULL)
{
printf("The Dynamic memory allocation is fail\n");
exit(-1);
}
pNew->users_sockaddr=uaddr;
pNew->user_fd=fd;
while(p->Next)
{
p=p->Next;
}
p->Next=pNew;
pNew->Next=NULL;
return;
}
void delet_List(pUSER_List p,int fd)
{
pUSER_List q;
do
{
q=p;//先保存前一个地址
p=p->Next;
if(p->user_fd==fd)
{
q->Next=p->Next;
free(p);
}
}while(p->Next);
}
char * choosechatmode(int sockfd,char *c)
{ int sendbytes,fd;
printf("Please choose the many people chat?or single people chat\n\n");
printf("many people chat please input manp\n");
printf("single people chat please input sinp\n");
scanf("%s",c);
while((strcmp("sinp",c)!=0)&&(strcmp("manp",c)!=0))
{
printf("Please input the correct command!!\n");
scanf("%s",c);
}
return c;
}
void show_online_users_list(pUSER_List USER)
{
printf("The online user list:--------------------------------\n");
do
{
USER=USER->Next;
printf("USER Socket is %d:",USER->user_fd);
printf(" The USER IP:%s\n",(char*)inet_ntoa(USER->users_sockaddr.sin_addr));
}while(USER->Next->Next);
printf("******************************************************\n");
}
int chack_socket_number(pUSER_List USER,int fd)
{
while(USER->Next)
{
if(USER->user_fd==fd)return 0;//说明上线用户列表中有这个用户
USER=USER->Next;
}
printf("The socket number In the online_user list is not exit!!!\n");
return 1;
}
int main(int argc, char *argv[])
{
pUSER_List USER,zero;
USER_List buff;
USER_List rebuff;
int recvbytes;
int sockfd, sendbytes;
struct hostent *host;
struct sockaddr_in serv_addr;
char c[10];
USER=craet_USER_listhead();//创建用户列表文件? zero=USER;
zero=USER;
pid_t child;
int fd;
/*地址解析函数*/
if ((host = gethostbyname(argv[1])) == NULL)
{
perror("gethostbyname");
exit(1);
}
/*创建socket*/
if ((sockfd = socket(AF_INET,SOCK_STREAM,0)) == -1)
{
perror("socket");
exit(1);
}
/*设置sockaddr_in 结构体中相关参数*/
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT);
serv_addr.sin_addr = *((struct in_addr *)host->h_addr);
bzero(&(serv_addr.sin_zero), 8);
/*调用connect函数主动发起对服务器端的连接*/
if(connect(sockfd,(struct sockaddr *)&serv_addr, sizeof(struct sockaddr))== -1)
{
perror("connect");
exit(1);
}
//接收用户在线用户列表
while(1)
{
memset(&buff,0,sizeof(USER_List));
if ((recvbytes = recv(sockfd, &buff, sizeof(USER_List), 0)) < 0)
{
perror("recv");
}
insert_USERList(USER,buff.users_sockaddr,buff.user_fd,"r");
if(buff.user_fd==6000)break;//如果接收到这个标志位,就说明接收完毕
}
show_online_users_list(USER);//显示在线用户列表
choosechatmode(sockfd,c);//群聊还是私聊模式选择
/*发送消息给服务器端*/
memset(&buff,0,sizeof(USER_List));
if(strcmp(c,"sinp")==0)//如果选择单人聊天模式
{
do
{
printf("Please input the user liner number!!\n");
scanf("%d",&fd);
buff.rece_id=fd;//就把选择目标ID存入。
}while(chack_socket_number(USER,fd));//检查目标ID是否在上线用户列表中
}
strcpy(buff.buf,c);//把聊天模式选择标志位加入数组头
printf("You can chat now!\n");
/* 创建子进程 */
if((child=fork())==-1)
{
printf("Fork Error \n");
exit(1);
}
while(1)
{
if(child==0) // 子进程
{
scanf("%s",buff.buf+4);
if(strncmp("sinp",buff.buf+4,4)==0)//如果切换到私聊模式
{
show_online_users_list(USER);//显示在线用户列表
do
{
printf("Please input the user liner number!!\n");
scanf("%d",&fd);
buff.rece_id=fd;//就把选择目标ID存入。
}while(chack_socket_number(USER,fd));//检查目标ID是否在上线用户列表中
strcpy(buff.buf,"sinp");//把聊天模式选择标志位加入数组头
}
else if(strncmp("manp",buff.buf+4,4)==0)
{
strcpy(buff.buf,"manp");//把聊天模式选择标志位加入数组头
}
if ((sendbytes = send(sockfd, &buff,sizeof(USER_List), 0)) == -1)
{
perror("send");
exit(1);
}
}
else if(child>0)//父进程
{
memset(&rebuff, 0, sizeof(USER_List));
if (recv(sockfd, &rebuff,sizeof(USER_List), 0) > 0)
{
if(strcmp(rebuff.del,"del")==0)//判断是否有人离线
{
printf("\33[33m\33[1m");
printf("The %d is outline!!\n",rebuff.user_fd);
printf("\33[0m\n");
delet_List(USER,rebuff.user_fd);//将下线用户从用户列表中删除
}
if(strcmp(rebuff.del,"inl")==0)//判断是否有人上线
{
printf("\33[33m\33[1m");
printf("The %d is inline!!\n",rebuff.user_fd);
printf("\33[0m\n");
insert_USERList(USER,rebuff.users_sockaddr,rebuff.user_fd,"w");//将新上线用户追加到列表
}
else
{
printf("\33[33m\33[1m");
printf("Received %d:%s\n",rebuff.rece_id,rebuff.buf+4);
printf("\33[0m\n");
}
}
}
}
close(sockfd);
exit(0);
}