【转】select+TCP/IP 实例片段(供参考)

转自:http://aea.web.psi.ch/Urs_Rohrer/MyWeb/sample1.htm

 

The following program prints onto the screen a list of the DAC and ADC values of all devices (command = RALL) of a given beam line. You may run this program test by  entering the command 'test Server_Name Port_ID'. It is also possible to redirect the generateded output list to a file by appending a third parameter to the command line [ >File_Name ].

 

 

/*=====================================================
  |  Demo program for remote CAMAC access via TCP/IP  |
  =====================================================*/

#ifdef WIN32
#include <windows.h>
#include <process.h>
#include <stddef.h>
#include <stdlib.h>
#include <winsock.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <memory.h>
#include <time.h>
#include <ctype.h>
#include <io.h>
#include <share.h>
#include <fcntl.h>
#include <sys\stat.h>
#else  /* Unix */
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/shm.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <pthread.h>
#include <ctype.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#endif

#define	MAXLEN	    2048	/* max command buffer length */
#define	BACKLOG	    5		/* max outstanding connections	*/
#define	FLAGS	    0		/* flags argument, must be zero	*/
#ifdef WIN32
#define errno WSAGetLastError()
#else
#define closesocket close
#define SOCKET int
#endif

SOCKET	l_socket;

int DataTransfer(char *command_s, char *r_buffer)
{
   int	   count, z, status;
   struct  timeval timeout;
   fd_set  readfds;
   int     msecs = 4000;

   count = send ( l_socket, command_s, strlen(command_s) + 1, FLAGS ); // zero-terminated
   if ( count == -1)
   {
        printf ("** Error sending data **\n");
        return 0;
   }

   z = 0;
   while(1)
   {
      if (msecs > 0)
      {
	 FD_ZERO(&readfds);
	 FD_SET(l_socket,&readfds);
	 timeout.tv_sec  = msecs / 1000;
	 timeout.tv_usec = (msecs % 1000) * 1000;
	 status = select(FD_SETSIZE, &readfds, NULL, NULL, &timeout);
	 if (status == -1)
	 {
            printf ("** Error while selecting **\n");
	    return 0;
	 }
	 if (!FD_ISSET(l_socket,&readfds))
	 {
	    printf ("** Timeout while selecting **\n");
	    r_buffer[z] = '\0';  // terminate it by adding a '\0'
	    z++;
	    break;
	 }
      }

      count = recv ( l_socket, &r_buffer[z], MAXLEN, FLAGS );
      if ( count == -1 )
      {
         printf ("** Error receiving answer **\n");
         return 0;
      }
      else
         z += count;

      if (r_buffer[z-1] == '\0')  // termination has arrived
	 break;
   }

   return z;
}

void Display(void)
{
    char buffer[MAXLEN];
    char command[MAXLEN];

    sprintf(command,"RALL");
    DataTransfer(command,buffer);

    /* reservation ok */

    if ( buffer[7] != '0' )
    {
        printf("%s\n",&buffer[6]);
    }
}

int main (int argc, char *argv[])
{
   int	status;
   int	shutdown_required = 0;
   char	localhost_s[20];
   char	remothost_s[20];

   struct  sockaddr_in	l_socket_s;
   struct  sockaddr_in	r_socket_s;

   struct  hostent *localhost_p;
   struct  hostent *remothost_p;

   unsigned long non_blocking = 1 ;
   unsigned long blocking = 0 ;
   struct  timeval timeout;
   fd_set  readfds, writefds;
   int     msecs = 4000;
   int     error=0, len;

#ifdef WIN32
   WORD    wVersionRequested;
   WSADATA wsaData;
   int     err;
#else
   typedef struct sockaddr *LPSOCKADDR;
#endif

    /* Check argument list length */

    if (argc != 3)
    {
        printf("Usage: client Servername ServerPort\n");
        exit(1);
    }

    /*  Start WinSocket-DLL  */

#ifdef WIN32
    wVersionRequested = MAKEWORD(1,1);
    err = WSAStartup(wVersionRequested,&wsaData);
    if (err != 0)
    {
	printf ("** WinSocket-DLL not found **\n");
	exit(1);
    }
#endif

    /*	Create a socket  */

    l_socket	=   socket ( AF_INET, SOCK_STREAM, 0 );
    if ( l_socket == -1 )
    {
	printf ("** Error Creating Socket **\n");
	exit(1);
    }

    /*	Get hostname  */

    gethostname(localhost_s,sizeof(localhost_s));
    localhost_p   =   gethostbyname ( localhost_s );
    if ( localhost_p == NULL )
    {
        printf ("** Cannot get hostaddress of %s **\n",localhost_s);
        exit(1);
    }

    /*	bind socket to port  */
    
    l_socket_s.sin_family	=   AF_INET;
    l_socket_s.sin_port		=   htons ( 0 );
    l_socket_s.sin_addr.s_addr	=   0;
    memcpy((char*)&(l_socket_s.sin_addr), localhost_p->h_addr, localhost_p->h_length);

    status = bind ( l_socket, (LPSOCKADDR)&l_socket_s, sizeof(l_socket_s));

    if ( status == -1 )
    {
	printf ("** Error Binding Socket, errno = %d **\n",errno);
        shutdown ( l_socket , 2 );
	exit(1);
    }

    /*	Get Server name  */

    strcpy(remothost_s,argv[1]);
    remothost_p   =   gethostbyname ( remothost_s );
    if ( remothost_p == NULL )
    {
        printf ("** Cannot get remote address %s **\n", remothost_s);
        exit(1);
    }

    /*  Connect to Server socket  */

    r_socket_s.sin_family	=   AF_INET;
    r_socket_s.sin_port		=   htons ( (unsigned short)atol(argv[2]) );
    r_socket_s.sin_addr.s_addr	=   *(unsigned long *) *(remothost_p->h_addr_list);

    /*
	non-blocking connect (in case server is not there
	[e.g. power off]), see Stevens 2nd: /lib/connect_nob.c
    */

#ifdef WIN32
    ioctlsocket(l_socket,FIONBIO,&non_blocking);
#else
    ioctl(l_socket,FIONBIO,&non_blocking);
#endif
    status = connect ( l_socket, (LPSOCKADDR)&r_socket_s, sizeof(r_socket_s));
    if ( status == -1)
    {
	 FD_ZERO(&readfds);
	 FD_SET(l_socket,&readfds);
	 writefds = readfds;
	 timeout.tv_sec  = msecs / 1000;
	 timeout.tv_usec = (msecs % 1000) * 1000;
	 status = select(l_socket+1, (void *)&readfds, (void *)&writefds, NULL, (void *)&timeout);
	 if (status > 0 || status < 0)
	 {
	    if (FD_ISSET(l_socket,&readfds) || FD_ISSET(l_socket,&writefds))
	    {
		len = sizeof(error);
		if (getsockopt(l_socket, SOL_SOCKET, SO_ERROR, (char *)&error, &len) < 0)
		   goto error_ret;
	    }
	    else
		goto error_ret;
	    if (error) goto error_ret;
#ifdef WIN32
	    status = ioctlsocket(l_socket,FIONBIO,&blocking);
#else
	    ioctl(l_socket,FIONBIO,&blocking);
#endif
	 }
	 else if (status == 0)
	 {
error_ret:
	    printf ("** Error connecting to Server **\n");
            shutdown ( l_socket , 2 );
	    exit(1);
	 }
    }
    Display();
    closesocket( l_socket );
    exit(1);
    return 0;
}


 

Select在Socket编程中还是比较重要的,可是对于初学Socket的人来说都不太爱用Select写程序,他们只是习惯写诸如connect、accept、recv或recvfrom这样的阻塞程序(所谓阻塞方式block,顾名思义,就是进程或是线程执行到这些函数时必须等待某个事件的发生,如果事件没有发生,进程或线程就被阻塞,函数不能立即返回)。可是使用Select就可以完成非阻塞(所谓非阻塞方式non-block,就是进程或线程执行此函数时不必非要等待事件的发生,一旦执行肯定返回,以返回值的不同来反映函数的执行情况,如果事件发生则与阻塞方式相同,若事件没有发生则返回一个代码来告知事件未发生,而进程或线程继续执行,所以效率较高)方式工作的程序,它能够监视我们需要监视的文件描述符的变化情况——读写或是异常。下面详细介绍一下! Select的函数格式(我所说的是Unix系统下的伯克利socket编程,和windows下的有区别,一会儿说明): int select(int maxfdp,fd_set *readfds,fd_set *writefds,fd_set *errorfds,struct timeval *timeout); 先说明两个结构体: 第一,struct fd_set可以理解为一个集合,这个集合中存放的是文件描述符(file descriptor),即文件句柄,这可以是我们所说的普通意义的文件,当然Unix下任何设备、管道、FIFO等都是文件形式,全部包括在内,所以毫无疑问一个socket就是一个文件,socket句柄就是一个文件描述符。fd_set集合可以通过一些宏由人为来操作,比如清空集合FD_ZERO(fd_set *),将一个给定的文件描述符加入集合之中FD_SET(int ,fd_set *),将一个给定的文件描述符从集合中删除FD_CLR(int ,fd_set*),检查集合中指定的文件描述符是否可以读写FD_ISSET(int ,fd_set* )。一会儿举例说明。 第二,struct timeval是一个大家常用的结构,用来代表时间值,有两个成员,一个是秒数,另一个是毫秒数。 具体解释select的参数: int maxfdp是一个整数值,是指集合中所有文件描述符的范围,即所有文件描述符的最大值加1,不能错!在Windows中这个参数的值无所谓,可以设置不正确。 fd_set *readfds是指向fd_set结构的指针,这个集合中应该包括文件描述符,我们是要监视这些文件描述符的读变化的,即我们关心是否可以从这些文件中读取数据了,如果这个集合中有一个文件可读,select就会返回一个大于0的值,表示有文件可读,如果没有可读的文件,则根据timeout参数再判断是否超时,若超出timeout的时间,select返回0,若发生错误返回负值。可以传入NULL值,表示不关心任何文件的读变化。 fd_set *writefds是指向fd_set结构的指针,这个集合中应该包括文件描述符,我们是要监视这些文件描述符的写变化的,即我们关心是否可以向这些文件中写入数据了,如果这个集合中有一个文件可写,select就会返回一个大于0的值,表示有文件可写,如果没有可写的文件,则根据timeout参数再判断是否超时,若超出timeout的时间,select返回0,若发生错误返回负值。可以传入NULL值,表示不关心任何文件的写变化。 fd_set *errorfds同上面两个参数的意图,用来监视文件错误异常。 struct timeval* timeout是select的超时时间,这个参数至关重要,它可以使select处于三种状态,第一,若将NULL以形参传入,即不传入时间结构,就是将select置于阻塞状态,一定等到监视文件描述符集合中某个文件描述符发生变化为止;第二,若将时间值设为0秒0毫秒,就变成一个纯粹的非阻塞函数,不管文件描述符是否有变化,都立刻返回继续执行,文件无变化返回0,有变化返回一个正值;第三,timeout的值大于0,这就是等待的超时时间,即select在timeout时间内阻塞,超时时间之内有事件到来就返回了,否则在超时后不管怎样一定返回,返回值同上述。 返回值: 负值:select错误 正值:某些文件可读写或出错 0:等待超时,没有可读写或错误的文件
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值