/*
* =====================================================================================
*
* Filename: select.c
*
* Description:
*
* Version: 1.0
* Created: 2012年02月22日 22时18分07秒
* Revision: none
* Compiler: gcc
*
* Author: MaZheng (blog.youkuaiyun.com/mazheng1989), mazheng19891019@gmail.com
* Company: Dalian University Of Technology
*
* =====================================================================================
*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <sys/time.h>
#define PORT 1234 /* port that will be opened */
#define BACKLOG 5 /* number of allowed connections */
#define MAXDATASIZE 1000 /* */
struct Client{
int fd;
char *name;
struct sockaddr_in addr;/*client's address information*/
char *data;
};
typedef struct Client CLIENT;
void process_cli(CLIENT *client,char *recvbuf,int len);
void savedata(char * recvbuf,int len,char *data);
int main()
{
int i,maxi,maxfd,sockfd;
int nready;
ssize_t n;
fd_set rset,allset;
int listenfd,connectfd; /*socket descriptors*/
struct sockaddr_in server;/*server's address information*/
/*client's information*/
CLIENT client[FD_SETSIZE];
char recvbuf[MAXDATASIZE];
int sin_size;
/*create tcp socket*/
if((listenfd=socket(AF_INET,SOCK_STREAM,0))==-1)
{
/*handle exception*/
perror("creating socket failed.");
exit(1);
}
int opt=SO_REUSEADDR;
setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
bzero(&server,sizeof(server));
server.sin_family=AF_INET;
server.sin_port=htons(PORT);
server.sin_addr.s_addr=htonl(INADDR_ANY);
if(bind(listenfd,(struct sockaddr *)&server,sizeof(struct sockaddr))==-1)
{
/*handle exception*/
perror("bind() error.");
exit(1);
}
if(listen(listenfd,BACKLOG)==-1)
{
perror("listen() error\n");
exit(1);
}
sin_size=sizeof(struct sockaddr_in);
/*initialize for select*/
maxfd=listenfd;
maxi=-1;
for(i=0;i<FD_SETSIZE;i++)
{
client[i].fd=-1;
}
FD_ZERO(&allset);
FD_SET(listenfd,&allset);
while(1)
{
struct sockaddr_in addr;
rset=allset;
nready=select(maxfd+1,&rset,NULL,NULL,NULL);
if(FD_ISSET(listenfd,&rset))
{
/*new client connection */
/*accept connection*/
if((connectfd=accept(listenfd,(struct sockaddr*)&addr,&sin_size))==-1)
{
perror("accept() error.\n");
continue;
}
/*put new fd to client*/
for(i=0;i<FD_SETSIZE;i++)
{
if(client[i].fd<0)
{
client[i].fd=connectfd;//save descriptor
client[i].name=(char *)malloc(MAXDATASIZE);
client[i].addr=addr;
client[i].data=(char *)malloc(MAXDATASIZE);
client[i].name[0]='\0';
client[i].data[0]='\0';
printf("You got a connection from %s.",inet_ntoa(client[i].addr.sin_addr));
break;
}
}
if(i==FD_SETSIZE)
printf("too many clients.\n");
FD_SET(connectfd,&allset);//add new descriptor to set
if(connectfd>maxfd)
maxfd=connectfd;
if(i>maxi)
maxi=i;
if(--nready<=0)
continue;/*no more readable descriptors*/
for(i=0;i<=maxi;i++)
{
/*check all clients for data*/
if((sockfd=client[i].fd)<0)
continue;
if(FD_ISSET(sockfd,&rset))
{
if((n=recv(sockfd,recvbuf,MAXDATASIZE,0))==0)
{
/*connection closed by client*/
close(sockfd);
printf("client( %s )closed connection.User's data:%s\n",client[i].name,client[i].data);
FD_CLR(sockfd,&allset);
client[i].fd=-1;
free(client[i].name);
free(client[i].data);
}
else
{
process_cli(&client[i],recvbuf,n);
}
if(--nready<=0)
break;//no more readable descriptors
}
}
}
close(listenfd);
}
return 0;
}
void process_cli(CLIENT *client,char *recvbuf,int len)
{
char sendbuf[MAXDATASIZE];
recvbuf[len-1]='\0';
if(strlen(client->name)==0)
{
//get client's name from client
memcpy(client->name,recvbuf,len);
printf("client's name is %s.\n",client->name);
return ;
}
/*save client's data*/
printf("received client ( %s )message:%s\n",client->name,recvbuf);
/*save user's data*/
savedata(recvbuf,len,client->data);
int i1;
for( i1=0;i1<len-1;i1++)
{
sendbuf[i1]=recvbuf[len-i1-2];
}
sendbuf[len-1]='\0';
send(client->fd,sendbuf,strlen(sendbuf),0);
}
void savedata(char *recvbuf,int len,char *data)
{
int start=strlen(data);
int i;
for( i=0;i<len;i++)
{
data[start+i]=recvbuf[i];
}
}