2012-10-22 25 views
-1

我正在学习如何在服务器TCP套接字程序,其中客户端可以连接并等待命令......的recv()阅读()和send(),而无需等待

fd = open("/tmp/myFIFO", O_RDWR); 
if(fd<0){ 
    perror("open() error"); 
    exit(1); 
} 

do { 
    while ((nbytes = read(fd, buffer, sizeof(buffer)-1)) > 0) { 
     buffer[nbytes] = '\0'; 
     printf("%s\n", buffer); 
    } 
    err = recv(cFD, strbuf, sizeof(strbuf), 0); 
    if (err < 0) { 
     if (errno != EWOULDBLOCK) { 
      perror(" recv() failed"); 
      state = TRUE; 
     } 
     break; 
    } 

    if (err == 0) { 
     printf(" Connection closed\n"); 
     state = TRUE; 
     break; 
    } 

    dSize = err; 
    printf(" %d bytes received\n", dSize); 
    err = send(cFD, buffer, strlen(buffer), 0); 
    if (err < 0) { 
     perror(" send() failed"); 
     state = TRUE; 
     break; 
    } 
} while (TRUE); 

我刚刚得到的部分我有问题的代码。我正在读管道。我用它来发送消息给客户端..但我的问题是与recv。它在将从我的管道读取的数据发送到客户端之前等待客户端发送的数据。我想要发生的是每次我发送一个数据到我的管道,它直接到客户端,而不等待recv ..这怎么能做到?

下面是完整的代码:

#include <stdio.h> 
#include <stdlib.h> 
#include <sys/ioctl.h> 
#include <sys/socket.h> 
#include <sys/time.h> 
#include <netinet/in.h> 
#include <errno.h> 
#include <string.h> 
#include <sys/select.h> 
#include <sys/types.h> 
#include <unistd.h> 
#include <sys/stat.h> 
#include <fcntl.h> 
#include <pthread.h> 

#define TRUE    1 
#define FALSE   0 

typedef struct SERVER_FD{ 

int sPort; 
int serverFD; 
int smaxFD; 
int newFD; 


}sSD; 

int cFD, 
    dSize, 
    err, 
    start = 1, 
    state, 
    DescRead, 
    DCSERVER = FALSE; 

struct sockaddr_in addr, cli_addr; 
unsigned long ip; 
char strbuf[256]; 
socklen_t clilen; 
fd_set fdin, fduse; 

pid_t pid, sid; 

int fd=-1; 
int nbytes; 
char buffer[256]; 


void process(int ServerFD, int Port, int sMax, int NewSFD); 
void cleanUP(int i, int max); 
void dlogs(unsigned long ip); 
void daemonize(); 

main (int argc, char *argv[]) 
{ 
    sSD link; 
    sSD *sCon; 
    sCon = &link; 
    sCon->sPort = 53234; 

    fd = open("/tmp/myFIFO", O_RDWR); 
    if(fd<0){ 
     perror("open() error"); 
     exit(1); 
    } 

    printf("Starting Server-G\n"); 

    fcntl(fd, F_SETFL, 
    fcntl(fd, F_GETFL) | O_NONBLOCK); 
    sCon->serverFD = socket(AF_INET, SOCK_STREAM, 0); 
    if (sCon->serverFD != -1) { 
     err = setsockopt(sCon->serverFD, SOL_SOCKET, SO_REUSEADDR,(char *)&start, sizeof(start)); 
     if (err != -1) { 
      err = ioctl(sCon->serverFD, FIONBIO, (char *)&start); 
      if (err != -1){ 
       process(sCon->serverFD,sCon->sPort,sCon->smaxFD,sCon->newFD); 
      } 
      else{ 
       perror("ioctl() failed"); 
       close(sCon->serverFD); 
       exit(EXIT_FAILURE); 
      } 
     } 
     else{ 
      perror("setsockopt() failed"); 
      close(sCon->serverFD); 
      exit(EXIT_FAILURE); 
     } 
    } 
    else{ 
     perror("FAILED CONNECTING TO SOCKET"); 
     exit(EXIT_FAILURE); 
    } 
} 

void process(int ServerFD, int Port, int sMax, int NewSFD){ 
    bzero((char *) &addr, sizeof(addr)); 
    addr.sin_family  = AF_INET; 
    addr.sin_addr.s_addr = 0; 
    addr.sin_port  = htons(Port); 

    err = bind(ServerFD,(struct sockaddr *)&addr, sizeof(addr)); 
    if (err < 0) { 
     perror("bind() failed"); 
     close(ServerFD); 
     exit(EXIT_FAILURE); 
    } 

    daemonize(); 
    err = listen(ServerFD, 32); 
    if (err < 0) { 
     perror("listen() failed"); 
     close(ServerFD); 
     exit(EXIT_FAILURE); 
    } 
    clilen = sizeof(cli_addr); 
    FD_ZERO(&fdin); 
    sMax = ServerFD; 
    FD_SET(ServerFD, &fdin); 

    do { 
     fduse = fdin; 
     err = select(sMax + 1, &fduse, NULL, NULL, NULL); 
     if (err < 0) { 
      perror(" select() failed"); 
      break; 
     } 
     DescRead = err; 
     for (cFD=0; cFD <= sMax && DescRead > 0; ++cFD) { 
      if (FD_ISSET(cFD, &fduse)) { 
       DescRead -= 1; 
       if (cFD == ServerFD) { 
        do { 
         NewSFD = accept(ServerFD,(struct sockaddr *) &cli_addr, &clilen); 
         if (NewSFD < 0) { 
          if (errno != EWOULDBLOCK) { 
           perror(" accept() failed"); 
           DCSERVER = TRUE; 
          } 
          break; 
         } 
         ip = ntohl(cli_addr.sin_addr.s_addr); 
         printf(" Connection from %d.%d.%d.%d\n", 
          (int)(ip>>24)&0xff, 
          (int)(ip>>16)&0xff, 
          (int)(ip>>8)&0xff, 
          (int)(ip>>0)&0xff); 
          dlogs(ip); 
         FD_SET(NewSFD, &fdin); 
         if (NewSFD > sMax) 
          sMax = NewSFD; 
        } while (NewSFD != -1); 
       } 
       else { 
        state = FALSE; 
        do { 
         //PART WHERE I'm Having problems. 
         err = recv(cFD, strbuf, sizeof(strbuf), 0); 
         if (err < 0) { 
          if (errno != EWOULDBLOCK) { 
          perror(" recv() failed"); 
          state = TRUE; 
          } 
          break; 
         } 
         if (err == 0) { 
          printf(" Connection closed\n"); 
          state = TRUE; 
          break; 
         } 
         dSize = err; 
         printf(" %d bytes received\n", dSize); 
         while ((nbytes = read(fd, buffer, sizeof(buffer)-1)) > 0) { 
          buffer[nbytes] = '\0'; 
          printf("%s\n", buffer); 
         } 

         err = send(cFD, buffer, strlen(buffer), 0); 
         if (err < 0) { 
          perror(" send() failed"); 
          state = TRUE; 
          break; 
         } 
        } while (TRUE); 

        if (state) { 
         close(fd); 
         close(cFD); 
         FD_CLR(cFD, &fdin); 
         if (cFD == sMax) { 
          while (FD_ISSET(sMax, &fdin) == FALSE) 
           sMax -= 1; 
         } 
        } 
       } 
      } 
     } 
    } while (DCSERVER == FALSE); 
    cleanUP(cFD, sMax); 
} 

void cleanUP(int i, int max){ 
    for (i=0; i <= max; ++i) { 
     if (FD_ISSET(i, &fdin)) 
     close(i); 
    } 
} 

void dlogs(unsigned long ip){ 
    FILE* pFile = fopen("/sockF.txt", "a+"); 
    fprintf(pFile,"Connection from: %d.%d.%d.%d", 
        (int)(ip>>24)&0xff, 
        (int)(ip>>16)&0xff, 
        (int)(ip>>8)&0xff, 
        (int)(ip>>0)&0xff); 
    fclose(pFile); 
} 

void daemonize(){ 
    pid = fork(); 
    if(pid<0){ 
     perror("fork() failed"); 
     exit(EXIT_FAILURE); 
    } 
    if(pid>0){ 
     exit(EXIT_SUCCESS); 
    } 

    umask(0); 

    sid = setsid(); 
    if(sid<0){ 
     perror("setsid() failed"); 
     exit(EXIT_FAILURE); 
    } 

    if((chdir("/")) < 0){ 
     perror("failed changing directory"); 
     exit(EXIT_FAILURE); 
    } 
} 

样本输出:我使用telnet和腻子测试服务器

From Telnet: IP: 192.168.5.53 
Telnet 192.168.5.55 53234 

./socks 
Starting Server-G 
Connection from: 192.168.5.53 

现在,当Telnet是连接我用腻子将数据发送到管道等等服务器将读取它。

From Putty: 
echo "TEST" > /tmp/myFIFO 

的这里的问题是,每当我从腻子书面形式向管道发送数据的服务器等待telnet来发送数据则输出前,发送我写到管道中的数据。我怎样才能使recv和阅读工作在相同的tym,所以当我写入我的管道它将输出而不等待recv?

感谢

编辑:我也用线程读取管道,但它仍在等待服务器输出什么都读入到管前的recv()。

回答

4

使用selectpoll等待两个文件句柄上的事件,例如。 (使用poll

#include <poll.h> 

//... 

struct pollfd pfds[2]; 
int rc; 

/* Wait for input on either one of the fds */ 
pfds[0].fd = fd; 
pfds[0].events = POLLIN; 
pfds[1].fd = cFD; 
pfds[1].events = POLLIN; 

do { 
    /* Wait forever for something to happen */ 
    rc = poll(&pfds, 2, -1); 
    /* Error handling elided */ 
    if (pfds[0].revents & POLLIN) 
    { 
     /* Read from fd, change pfds[1].events to (POLLIN | POLLOUT) so you know when you 
      can write without blocking. also clear pfds[0].events so we don't read until we 
      write */ 
     pfds[0].events = 0; 
     pfds[1].events = POLLIN | POLLOUT; 
    } 

    if (pfds[1].revents & POLLIN) 
    { 
     /* Read from socket */ 
    } 

    if (pfds[1].revents & POLLOUT) 
    { 
     /* write to socket, reset events flags */ 
     pfds[0].events = POLLIN; 
     pfds[1].events = POLLIN; 
    } 
} while (1) 
+0

事实上,'select'几乎已经过时(它只能处理文件描述符少于256或1024),'poll'是使用 –

+0

谢谢伟大的答案正确的系统调用...我会删除我的代码选择部分?..或者只是在我的循环中添加此代码?..我可以结合选择和民意调查? – demic0de