unix select 模型

一.unix 规划下关于select 模式(服务器端)


1.建立socket套接字
int nsock = socket(AF_UNIX,SOCK_STREAM,0);

2.设置socket缓冲大小.
setsockopt(nsock, SOL_SOCKET, SO_REUSEADDR, &reuse_addr,sizeof(reuse_addr));

3.bind 服务器的地址到套接字

bind(nsock,(struct sockaddr *)&name,len);

4.建立侦听,此可以设置连接数
listen(nsock,5);

5.建立侦听线程,线程中调用accept等待客户端的连接
accept(nSock, (struct sockaddr *) &name, &len))

6.在线程中将套接字描述符及连接描述符加入FD_SET集中
int nSock; //为套接字描述符
fd_set fd_socks;//为FD集 异步I/O模型
int nconnectlist[MAX_CON];//连接描述符
unsigned int nMax_Sock ;//最大的描述符

void Build_Select()
{
 FD_ZERO(&fd_socks);
 FD_SET(nsock,&fd_socks);

 for(int i =0;i<MAX_CON;i++)
 {
     if(nconnectlist[i] != 0)
  FD_SET(nconnectlist[i],&fd_socks);
  if(nconnectlist[i]>nMax_Sock)
   nMax_Sock  = nconnectlist[i];
 }
}

在线程内结构如下:
while(TRUE)
{
 int nReadCount = select(nMax_Sock+1, &nsocks, (fd_set *) 0,
    (fd_set *) 0, &timeout);
 //select  有三个fd集,读,写,其它
 if(nReadCount<0)
 {
  printf("Select error/n");//select错误
 }
 else if (0=nReadCount)
 {
  printf("none/n");//没有可读数据
 }
 else
 {
  printf("read data");//有可读数据
  ReadSocket();//读数据函数
 }
}

void ReadSocket()
{
 if(FD_ISSET(nsock,&fd_socks);
 {
  //新客户端连接
 }
 for(int i =0;i<MAX_CON;i++)
 {
  if(FD_ISSET(nconnectlist[i],&fd_socks)
  {
   //读客户数据
  }
 }
}

7.关闭连接及套接字
for(int i =0;i<nconnectlist[i];i++)
{
 if(nconnectlist[i]>0)
  close(nconnectlist[i]);
}
close(nsock);


二.unix 规划下关于select 模式(客户端)
1.建立socket套接字
int nsock = socket(AF_UNIX,SOCK_STREAM,0);

2.设置socket缓冲大小.
setsockopt(nsock, SOL_SOCKET, SO_REUSEADDR, &reuse_addr,sizeof(reuse_addr));

3.连接服务器端
connect(nsock, (struct sockaddr *) &name, len);

4.建连接线程
fd_set fd_socks;//为FD集 异步I/O模型
int nconnectlist[MAX_CON];//连接描述符
unsigned int nMax_Sock ;//最大的描述符

nMax_Sock = nSock+1;

while(TRUE)
{
 FD_ZERO(&fd_socks);
 FD_SET(&nMax_Sock,&fd_socks);
 FD_SET(0,&fd_socks);

 int nReadCount = select(nMax_Sock+1, &nsocks, (fd_set *) 0,
    (fd_set *) 0, &timeout);
 //select  有三个fd集,读,写,其它
 
 if(FD_ISSET(nsock,&fd_socks))
 {

  int readcount = recv(nsock,buf,len);//接收数据
  if(readcount<1)
  {
   close(nSock);//关闭连接
   exit(0);
  }
  write(1,buf,len);//向控制台写读入数据
 }
 if(FD_ISSET(0,&fd_set)
 {
  int readcount = read(0,buf,len);
  //读取标准输入 0为输入stdin,1为输出stdout,2错误stderr
  if(readcount <1)
  {
   close(nsock);
   exit(0);
  }
  send(nsock,buf,len);//发送数据
 }

}

5.关闭连接及套接字
close(nsock);

 

附:服务器程序

#include "sockhelp.h"
#include <ctype.h>
#include <sys/time.h>
#include <fcntl.h>

int sock;           
                     /* The socket file descriptor for our "listening"socket */
int connectlist[5];  /* Array of connected sockets so we know who we are talking to */

fd_set socks;        /* Socket file descriptors we want to wake up for, using select() */

int highsock;      /* Highest #'d file descriptor, needed for select() */

void setnonblocking(sock)
int sock;
{
 int opts;
 
 opts = fcntl(sock,F_GETFL);
 if (opts < 0) {
  perror("fcntl(F_GETFL)");
  exit(EXIT_FAILURE);
 }
 opts = (opts | O_NONBLOCK);
 if (fcntl(sock,F_SETFL,opts) < 0) {
  perror("fcntl(F_SETFL)");
  exit(EXIT_FAILURE);
 }
 return;
}

void build_select_list()
{
 int listnum;      /* Current item in connectlist for for loops */
 
       /* First put together fd_set for select(), which will
       consist of the sock veriable in case a new connection
       is coming in, plus all the sockets we have already
    accepted. */
 
 
    /* FD_ZERO() clears out the fd_set called socks, so that
 it doesn't contain any file descriptors. */
 
 FD_ZERO(&socks);
 
 /* FD_SET() adds the file descriptor "sock" to the fd_set,
 so that select() will return if a connection comes in
 on that socket (which means you have to do accept(), etc. */
 
 FD_SET(sock,&socks);
 
 /* Loops through all the possible connections and adds
 those sockets to the fd_set */
 
 for (listnum = 0; listnum < 5; listnum++)
 {
  if (connectlist[listnum] != 0)
  {
   FD_SET(connectlist[listnum],&socks);
   if (connectlist[listnum] > highsock)
    highsock = connectlist[listnum];
  }
 }
}

void handle_new_connection()
{
 int listnum;      /* Current item in connectlist for for loops */
 int connection; /* Socket file descriptor for incoming connections */
 
     /* We have a new connection coming in!  We'll
 try to find a spot for it in connectlist. */
 connection = accept(sock, NULL, NULL);
 if (connection < 0) {
  perror("accept");
  exit(EXIT_FAILURE);
 }
 setnonblocking(connection);
 for (listnum = 0; (listnum < 5) && (connection != -1); listnum ++)
  if (connectlist[listnum] == 0)
  {
   printf("/nConnection accepted:   FD=%d; Slot=%d/n",
    connection,listnum);
   connectlist[listnum] = connection;
   connection = -1;
  }
  if (connection != -1)
  {
   /* No room left in the queue! */
   printf("/nNo room left for new client./n");
   sock_puts(connection,"Sorry, this server is too busy. Try again later!/r/n");
   close(connection);
  }
}

void deal_with_data(int listnum)
/* Current item in connectlist for for loops */
{
 char buffer[80];     /* Buffer for socket reads */
 char *cur_char;      /* Used in processing buffer */
 
 if (sock_gets(connectlist[listnum],buffer,80) < 0)
 {
     /* Connection closed, close this end and free up entry in connectlist */
  printf("/nConnection lost: FD=%d;  Slot=%d/n", connectlist[listnum],listnum);
  close(connectlist[listnum]);
  connectlist[listnum] = 0;
 }
 else
 {
 /* We got some data, so upper case it
  and send it back. */
  printf("/nReceived: %s; ",buffer);
  cur_char = buffer;
  while (cur_char[0] != 0)
  {
   cur_char[0] = toupper(cur_char[0]);
   cur_char++;
  }
  sock_puts(connectlist[listnum],buffer);
  sock_puts(connectlist[listnum],"/n");
  printf("responded: %s/n",buffer);
 }
}

void read_socks()
{
 int listnum;     
 /* Current item in connectlist for for loops */
 
 /* OK, now socks will be set with whatever socket(s)
 are ready for reading.  Lets first check our
    "listening" socket, and then check the sockets
 in connectlist. */
 
    /* If a client is trying to connect() to our listening
 socket, select() will consider that as the socket
 being 'readable'. Thus, if the listening socket is
 part of the fd_set, we need to accept a new connection. */
 
 if (FD_ISSET(sock,&socks))
  handle_new_connection();
 /* Now check connectlist for available data */
 
 /* Run through our sockets and check to see if anything
 happened with them, if so 'service' them. */
 
 for (listnum = 0; listnum < 5; listnum++)
 {
  if (FD_ISSET(connectlist[listnum],&socks))
   deal_with_data(listnum);
 }
 /* for (all entries in queue) */
}

int main (argc, argv)
int argc;
char *argv[];
{
 char *ascport;  /* ASCII version of the server port */
 int port;       /* The port number after conversion from ascport */
 struct sockaddr_in server_address; /* bind info structure */
    int reuse_addr = 1;  /* Used so we can re-bind to our port
      while a previous connection is still
   in TIME_WAIT state. */
   struct timeval timeout;  /* Timeout for select */
   int readsocks;      /* Number of sockets ready for reading */
  
   /* Make sure we got a port number as a parameter */
   if (argc < 2) {
    printf("Usage: %s PORT/r/n",argv[0]);
    exit(EXIT_FAILURE);
   }
  
   /* Obtain a file descriptor for our "listening" socket */
   sock = socket(AF_INET, SOCK_STREAM, 0);
   if (sock < 0)
   {
    perror("socket");
    exit(EXIT_FAILURE);
   }
   /* So that we can re-bind to it without TIME_WAIT problems */
   setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse_addr,sizeof(reuse_addr));
  
   /* Set socket to non-blocking with our setnonblocking routine */
   setnonblocking(sock);
           
   /* Get the address information, and bind it to the socket */
    ascport = argv[1]; /* Read what the user gave us */
 port = atoport(ascport); /* Use function from sockhelp to
 convert to an int */
 memset((char *) &server_address, 0, sizeof(server_address));
 server_address.sin_family = AF_INET;
 server_address.sin_addr.s_addr = htonl(INADDR_ANY);
 server_address.sin_port = port;
 if (bind(sock, (struct sockaddr *) &server_address,
   sizeof(server_address)) < 0 )
 {
   perror("bind");
   close(sock);
   exit(EXIT_FAILURE);
 }

 /* Set up queue for incoming connections. */
 listen(sock,5);

 /* Since we start with only one socket, the listening socket,
 it is the highest socket so far. */
 highsock = sock;
 memset((char *) &connectlist, 0, sizeof(connectlist));

 while (1)
 { /* Main server loop - forever */
   build_select_list();
   timeout.tv_sec = 1;
   timeout.tv_usec = 0;
 
   /* The first argument to select is the highest file
   descriptor value plus 1. In most cases, you can
   just pass FD_SETSIZE and you'll be fine. */
 
   /* The second argument to select() is the address of
   the fd_set that contains sockets we're waiting
   to be readable (including the listening socket). */
 
   /* The third parameter is an fd_set that you want to
   know if you can write on -- this example doesn't
   use it, so it passes 0, or NULL. The fourth parameter
   is sockets you're waiting for out-of-band data for,
   which usually, you're not. */
 
   /* The last parameter to select() is a time-out of how
   long select() should block. If you want to wait forever
   until something happens on a socket, you'll probably
   want to pass NULL. */
 
   readsocks = select(highsock+1, &socks, (fd_set *) 0,
    (fd_set *) 0, &timeout);
 
    /* select() returns the number of sockets that had
   things going on with them -- i.e. they're readable. */
 
   /* Once select() returns, the original fd_set has been
   modified so it now reflects the state of why select()
   woke up. i.e. If file descriptor 4 was originally in
   the fd_set, and then it became readable, the fd_set
   contains file descriptor 4 in it. */
 
   if (readsocks < 0) {
    perror("select");
    exit(EXIT_FAILURE);
   }
   if (readsocks == 0) {
   /* Nothing ready to read, just show that
    we're alive */
    printf(".");
    fflush(stdout);
   } else
    read_socks();
 } /* while(1) */
} /* main */

 

2.客户端程序

/* pollcli.c */
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <sys/un.h>
#include <sys/time.h>
#include <fcntl.h>
#define SOCKETNAME  "/faculty/rossa/system/mysocket"

int
main(void)
{
 int s;  /* This end of connection*/
 int len; /* length of sockaddr */
 int nread; /* return from read() */
 int nready; /* # fd's ready. */
 int maxfd; /* fd's 0 to maxfd-1 checked. */
 char buf[1024];
 fd_set fds; /* set of file descriptors to check. */
 struct sockaddr_un name;
 
 
 if( (s = socket(AF_UNIX, SOCK_STREAM, 0) ) < 0){
  perror("socket");
  exit(1);
 }
 
 /*Create the address of the server.*/
 
 memset(&name, 0, sizeof(struct sockaddr_un));
 
 name.sun_family = AF_UNIX;
 strcpy(name.sun_path, SOCKETNAME);
 len = sizeof(name.sun_family) + strlen(name.sun_path);
 
 
 /*Connect to the server.*/
 
 if (connect(s, (struct sockaddr *) &name, len) < 0){
  perror("connect");
  exit(1);
 }
 
 
 maxfd = s + 1;
 while(1){
  /* Set up polling. */
  FD_ZERO(&fds);
  FD_SET(s,&fds);
  FD_SET(0,&fds);
  
  /* Wait for some input. */
  nready = select(maxfd, &fds, (fd_set *) 0, (fd_set *) 0,
   (struct timeval *) 0);
  
   /* If either device has some input,
  read it and copy it to the other. */
  
  if( FD_ISSET(s, &fds))
  {
   nread = recv(s, buf, sizeof(buf), 0);
   /* If error or eof, terminate. */
   if(nread < 1){
    close(s);
    exit(0);
   }
   write(1, buf, nread);
  }
  
  if( FD_ISSET(0, &fds))
  {
   nread = read(0, buf, sizeof(buf));
   /* If error or eof, terminate. */
   if(nread < 1){
    close(s);
    exit(0);
   }
   send( s, buf, nread, 0);
  }
 }
 
}

你可能感兴趣的:(unix select 模型)