-1

我正在学习如何编写服务器 TCP 套接字,其中客户端可以连接并等待命令......

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。它在将从我的管道读取的数据发送到客户端之前等待客户端发送的数据。我想要发生的是每次我将数据发送到我的管道时,它会直接发送到客户端而无需等待接收。这怎么办?

这是完整的代码:

#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 和 putty 来测试服务器

From Telnet: IP: 192.168.5.53
Telnet 192.168.5.55 53234

./socks
Starting Server-G
Connection from: 192.168.5.53

现在,当连接 telnet 时,我使用 putty 将数据发送到管道,以便服务器读取它。

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

这里的问题是,每当我将数据从腻子写入管道发送到管道时,服务器都会等待 telnet 在输出之前发送数据并将我写入的数据发送到管道。我怎样才能让recv和read在同一个时间工作,所以当我写到我的管道时,它会在不等待recv的情况下输出?

谢谢

编辑:我也使用线程来读取管道,但它仍然等待 recv() 在服务器输出已读取到管道的内容之前。

4

1 回答 1

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)
于 2012-10-22T10:04:14.067 回答