/* net_select.c */
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <netinet/in.h>
#include<malloc.h>
#define PORT 4321
#define MAX_QUE_CONN_NM 5
#define MAX_SOCK_FD FD_SETSIZE
#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;//目标用户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 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);
}
void sendlist_usr(pUSER_List p,int sockfd)
{
USER_List end,buff;
int sendbytes;
end.user_fd=6000;
//送消息给客户端
while(p->Next)
{
p=p->Next;
memset(&buff,0,sizeof(USER_List));
buff.users_sockaddr=p->users_sockaddr;
buff.user_fd=p->user_fd;
buff.user_name="w";
if ((sendbytes = send(sockfd,&buff,sizeof(USER_List), 0)) == -1)
{
perror("send");
exit(1);
}
}
if ((sendbytes = send(sockfd,&end,sizeof(USER_List), 0)) == -1)//发射结束标志
{
perror("send");
exit(1);
}
}
void manypeople_chat_fun(pUSER_List USER,int fd,USER_List buff)
{
int sendbytes;
while(USER->Next)
{
USER=USER->Next;
printf("%d\n",USER->user_fd);
strcpy(USER->buf,buff.buf);
strcpy(USER->del,buff.del);
if(USER->user_fd!=fd)
{
if ((sendbytes=send(USER->user_fd,USER,sizeof(USER_List), 0)) == -1)
{
perror("send");
exit(1);
}
}
}
}
void singlepeople_chat_fun(int target,USER_List USER)
{
int sendbytes;
if ((sendbytes=send(target,&USER,sizeof(USER_List), 0)) == -1)
{
perror("send");
exit(1);
}
}
int main()
{
pUSER_List USER,REUSER;
int sendbytes;
struct sockaddr_in server_sockaddr, client_sockaddr;
int sin_size, count;
fd_set inset, tmp_inset;
int sockfd, client_fd, fd;
u_long hbuff;
char bufsym[5];
USER=craet_USER_listhead();//创建用户列表文件头
REUSER=USER;
USER_List buff;
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)//创建套接字
{
perror("socket");
exit(1);
}
server_sockaddr.sin_family = AF_INET;
server_sockaddr.sin_port = htons(PORT);
server_sockaddr.sin_addr.s_addr = INADDR_ANY;
bzero(&(server_sockaddr.sin_zero), 8);
int i = 1;/* 使得重复使用本地地址与套接字进行绑定 */
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i));
if (bind(sockfd, (struct sockaddr *)&server_sockaddr, sizeof(struct sockaddr)) == -1)
{
perror("bind");
exit(1);
}
printf("%s\n",(char *)inet_ntoa(&server_sockaddr.sin_addr));
if(listen(sockfd, MAX_QUE_CONN_NM) == -1)
{
perror("listen");
exit(1);
}
printf("listening....\n");
/*将调用socket函数的描述符作为文件描述符*/
FD_ZERO(&inset);//初始化套接字集合
FD_SET(sockfd, &inset);//select()机制中提供一fd_set的数据结构,实际上是一long类型的数组?
//每一个数组元素都能与一打开的文件句柄(不管是socket句柄,还是其他文件或命名管道或设备句柄)建立联系
while(1)
{
tmp_inset = inset;
sin_size=sizeof(struct sockaddr_in);
memset(&buff, 0, sizeof(USER_List));
/*调用select函数*/
printf("select....\n");
if (!(select(MAX_SOCK_FD, &tmp_inset, NULL, NULL, NULL) > 0))
{
perror("select");
close(sockfd);
exit(1);
}
for (fd = 0; fd < MAX_SOCK_FD; fd++)
{
if (FD_ISSET(fd, &tmp_inset) > 0)
{
if (fd == sockfd)
{ /* 服务端接收客户端的连接请求 */
if ((client_fd = accept(sockfd, (struct sockaddr *)&client_sockaddr, &sin_size))== -1)
{
perror("accept");
exit(1);
}
FD_SET(client_fd, &inset);
strcpy(buff.del,"inl");//用户上线标志置位
manypeople_chat_fun(USER,fd,buff);//进入群聊模式把上线信息发给说有在线用户
strcpy(buff.del,"onl");
insert_USERList(USER,client_sockaddr,client_fd,"w");//插入登陆用户信息
printf("%d\n",USER->user_fd);
sendlist_usr(USER,client_fd);//把在线的用户发给客户机
//printf(" client IP:%s\n",(char*)inet_ntoa(client_sockaddr.sin_addr));
}
else /* 处理从客户端发来的消息 */
{
if ((count = recv(fd, &buff,sizeof(USER_List), 0)) > 0)
{
strncpy(bufsym,buff.buf,4);
if(strcmp(bufsym,"sinp")==0)//如果用户选择私聊
{
singlepeople_chat_fun(buff.rece_id,buff);
}
if(strcmp(bufsym,"manp")==0)//如果用户选择公聊
{
USER=REUSER;
manypeople_chat_fun(USER,fd,buff);
}
}
else
{
close(fd);
FD_CLR(fd, &inset);
delet_List(USER,fd);//将下线用户删除在线用户列表
strcpy(buff.del,"del");
buff.rece_id=fd;
manypeople_chat_fun(USER,fd,buff);//给客户端发送由用户离开信号
strcpy(buff.del,"onl");
printf("Client %d(socket) has left\n", fd);
}
}
} /* end of if FD_ISSET*/
} /* end of for fd*/
} /* end if while while*/
close(sockfd);
exit(0);
}