2012-10-06 124 views
-1

我试图创建两个程序:一个基本套接字服务器和一个客户端,它们都将在Linux机器上运行。服务器的指令是建立一个套接字,接受一个传入的客户端请求,使用信号建立一个处理程序(用于读取数据缓冲区),然后输入一个无限的睡眠循环。客户端的指令是建立一个套接字,连接到服务器,并发送一个数据缓冲区。我希望按照单个客户端连接的描述来工作,然后再担心关闭连接并启动一个新连接(不确定这些事情应该循环到哪里,我试图保持简单。)我也了解到,信号被弃用,因此,我试图用的sigaction按照这里的例子:无法获取sigaction工作

http://www.linuxprogrammingblog.com/code-examples/sigaction

不幸的是,当我运行我的代码会发生什么情况是这样的:

  1. 服务器启动
  2. 服务器设置插座
  3. 服务器开始侦听和盖帽上接受(等待客户端)
  4. 客户推出
  5. 客户端设置了插座
  6. 客户端连接到服务器
  7. 服务器疏导
  8. 服务器设置的sigaction
  9. Server开始睡觉
  10. 客户端调用写
  11. 客户端似乎成功写(主知道在哪里到)
  12. 等待字节的客户端块从服务器读取确认
  13. 服务器还在睡觉(的sigaction从不触发)

这里是我的服务器当前的代码:

#include <sys/types.h> // socket, bind 
#include <sys/socket.h> // socket, bind, listen, inet_ntoa 
#include <netinet/in.h> // htonl, htons, inet_ntoa 
#include <arpa/inet.h> // inet_ntoa 
#include <netdb.h>  // gethostbyname 
#include <unistd.h>  // read, write, close 
#include <string.h>  // bzero 
#include <netinet/tcp.h> // SO_REUSEADDR 
#include <sys/uio.h>  // writev 
#include <signal.h>  // sigaction 
#include <sys/time.h>  // gettimeofday 
#include <unistd.h>  // write 
#include <fcntl.h>  // fcntl 
#include <iostream>  // cout 

using namespace std; 
#define BUFSIZE 1500 

// Globals 
int nreps; 
int nbufs; 
int newSd; 

// Read all the data from the client and output how long it took 
void readFromClient(int sig, siginfo_t *siginfo, void *context) 
{ 
    cout << "readFromClient triggered!" << endl; 

    /* 
    // Set up asynchronous communication 
    int fd = siginfo->si_fd; 
    fcntl(fd, F_SETOWN, getpid()); 
    fcntl(fd, F_SETFL, FASYNC); 
    */ 

    // Declare data buffer 
    char databuf[BUFSIZE]; 

    // Record start time 
    struct timeval theTime; 
    gettimeofday(&theTime, NULL); 
    int startTime = theTime.tv_usec + theTime.tv_sec * 1000000; 

    // Keep reading until the buffer is full 
    int nRead = 0; 
    /* 
    while((nRead += read(newSd, databuf, BUFSIZE - nRead)) < BUFSIZE) 
    { 
     cout << "nRead now: " << nRead << endl; 
    } 
    */ 

    // For testing single byte read 
    cout << "Reading a byte... " << endl; 
    char bytebuf[1]; 
    read(newSd, bytebuf, 1); 
    cout << "SUCCESS" << endl; 

    // Record finish time 
    gettimeofday(&theTime, NULL); 
    int finishTime = theTime.tv_usec + theTime.tv_sec * 1000000; 

    // Calculate the receiving time 
    int receiveTime = finishTime - startTime; 

    // Display the receiving time 
    cout << "data-receiving time = " << receiveTime << " usec" << endl; 

    // Tell the client how much data was read 
    cout << "Writing amount read... " << endl; 
    write(newSd, (void*)nRead, 4); 
    cout << "SUCCESS" << endl; 

    // Close the socket 
    cout << "Closing socket... " << endl; 
    close(newSd); 
    cout << "SUCCESS" << endl; 

    // Exit the program 
    cout << "Exiting!" << endl; 
    exit(0); 
    cout << "Why are you still here?" << endl; 
} 

int main(int argc, char *argv[]) 
{ 
    cout << "Server is running!" << endl; 

    // Store command line arguments 
    int port = atoi(argv[1]); 
    int nreps = atoi(argv[2]); 
    int nbufs = atoi(argv[3]); 
    cout << "port: " << port << endl; 
    cout << "nreps: " << nreps << endl; 
    cout << "nbufs: " << nbufs << endl; 

    // Declare a socket 
    sockaddr_in acceptSockAddr; 
    memset((char*)&acceptSockAddr, '\0', sizeof(acceptSockAddr)); 
    acceptSockAddr.sin_family = AF_INET; // Address Family Internet 
    acceptSockAddr.sin_addr.s_addr = htonl(INADDR_ANY); 
    acceptSockAddr.sin_port = htons(port); // convert host byte-order 

    // Open a stream-oriented socket 
    int serverSd = socket(AF_INET, SOCK_STREAM, 0); 

    // Signal OS to reuse this port once server closes 
    const int on = 1; 
    setsockopt(serverSd, SOL_SOCKET, SO_REUSEADDR, (char*)&on, sizeof(int)); 

    // Bind socket to local address 
    bind(serverSd, (sockaddr*)&acceptSockAddr, sizeof(acceptSockAddr)); 

    // Instruct OS to listen for up to 5 clients 
    listen(serverSd, 5); 

    // Declare a new socket 
    sockaddr_in newSockAddr; 
    socklen_t newSockAddrSize = sizeof(newSockAddr); 
    int newSd; 

    // Set up signal handler for IO from client 
    struct sigaction action; 
    memset(&action, '\0', sizeof(action)); 
    action.sa_sigaction = &readFromClient; 
    action.sa_flags = SA_SIGINFO; 
    //fcntl(newSd, F_SETSIG, SIGIO); // Fixes problem with si_fd 
    if(sigaction(SIGIO, &action, NULL) < 0) 
    { 
     perror("sigaction"); 
     return 1; 
    } 

    // sleep forever 
    cout << "Sleeping..." << endl; 
    while(1) 
    { 
     cout << "Waiting for client... " << endl; 
     newSd = accept(serverSd, (sockaddr*)&newSockAddr, &newSockAddrSize); 
     cout << "SUCCESS" << endl; 

     cout << "Switching to asynchronous communication... " << endl; 
     fcntl(newSd, F_SETOWN, getpid()); 
     fcntl(newSd, F_SETFL, FASYNC); 
     cout << "SUCCESS" << endl; 

     cout << "Resuming sleep... " << endl; 
     sleep(10); 
    } 
    return 0; 
} 

这里是我的客户端当前的代码:

#include <sys/types.h> // socket, bind 
#include <sys/socket.h> // socket, bind, listen, inet_ntoa 
#include <netinet/in.h> // htonl, htons, inet_ntoa 
#include <arpa/inet.h> // inet_ntoa 
#include <netdb.h>  // gethostbyname 
#include <unistd.h>  // read, write, close 
#include <string.h>  // bzero 
#include <netinet/tcp.h> // SO_REUSEADDR 
#include <sys/uio.h>  // writev 
#include <signal.h>  // sigaction 
#include <sys/time.h>  // gettimeofday 
#include <unistd.h>  // write 
#include <fcntl.h>  // fcntl 
#include <iostream>  // cout 

using namespace std; 
#define BUFSIZE 1500 
#define SIZEOFINT 4 

int main(int argc, char *argv[]) 
{ 
    cout << "Client is running!" << endl; 

    // Store commmand line arguments 
    int server_port = atoi(argv[1]); 
    int nreps = atoi(argv[2]); 
    int nbufs = atoi(argv[3]); 
    int bufsize = atoi(argv[4]); 
    const char* server_name = argv[5]; 
    int testType = atoi(argv[6]); 
    cout << "server_port: " << server_port << endl; 
    cout << "nreps: " << nreps << endl; 
    cout << "nbufs: " << nbufs << endl; 
    cout << "bufsize: " << bufsize << endl; 
    cout << "server_name: " << server_name << endl; 
    cout << "testType: " << testType << endl; 

    // Check to ensure proper buffer count/sizes 
    if(nbufs * bufsize != BUFSIZE) 
    { 
     cout << "nbufs times bufsize must equal " << BUFSIZE << endl; 
     exit(0); 
    } 

    if(testType < 1 || testType > 3) 
    { 
     cout << "test type must be 1, 2, or 3" << endl; 
     exit(0); 
    } 

    // Create buffers 
    char databuf[nbufs][bufsize]; 

    // Retrieve hostent structure 
    struct hostent* host = gethostbyname(server_name); 

    // Declare socket structure 
    sockaddr_in sendSockAddr; 
    memset((char*)&sendSockAddr, '\0', sizeof(sendSockAddr)); 
    sendSockAddr.sin_family = AF_INET; // Address Family Internet 
    sendSockAddr.sin_addr.s_addr = inet_addr(inet_ntoa(*(struct in_addr*)*host->h_addr_list)); 
    sendSockAddr.sin_port = htons(server_port); // convert host byte-order 

    // Open stream-oriented socket 
    int clientSd = socket(AF_INET, SOCK_STREAM, 0); 

    // Connect socket to server 
    cout << "Connecting socket to server... " << endl; 
    int code = connect(clientSd, (sockaddr*)&sendSockAddr, sizeof(sendSockAddr)); 
    cout << "Connection result: " << code << endl; 

    // Record start time 
    struct timeval theTime; 
    gettimeofday(&theTime, NULL); 
    int startTime = theTime.tv_usec + theTime.tv_sec * 1000000; 

    // Conduct tests 
    for(int i = 0; i < nreps; i++) 
    { 
     switch(testType) 
     { 
      case 1: 
      { 
       // Multiple write test 
       cout << "Running multiple write test" << endl; 
       for(int j = 0; j < nbufs; j++) 
       { 
        cout << "Writing buffer " << j << "... " << endl; 
        write(clientSd, databuf[j], bufsize); 
        cout << "SUCCESS" << endl; 
       } 
       cout << "Finished multiple write test" << endl; 
      } 
      case 2: 
      { 
       // Vector write test 
       cout << "Running vector write test" << endl; 
       struct iovec vector[nbufs]; 
       for(int j = 0; j < nbufs; j++) 
       { 
        vector[j].iov_base = databuf[j]; 
        vector[j].iov_len = bufsize; 
       } 
       cout << "Writing vector... " << endl; 
       writev(clientSd, vector, nbufs); 
       cout << "SUCCESS" << endl; 
       cout << "Finished vector write test" << endl; 
      } 
      case 3: 
      { 
       // Single write test 
       cout << "Running single write test" << endl; 

       /* 
       cout << "Writing... "; 
       write(clientSd, databuf, nbufs * bufsize); 
       cout << "SUCCESS" << endl; 
       */ 

       // For testing single byte write 
       cout << "writing a byte..." << endl; 
       char singleByte[1]; 
       write(clientSd, singleByte, 1); 
       cout << "wrote a byte!" << endl; 

       cout << "Finished single write test" << endl; 
      } 
     } 
    } 

    // Record finish time 
    gettimeofday(&theTime, NULL); 
    int finishTime = theTime.tv_usec + theTime.tv_sec * 1000000; 

    // Calculate the sending time 
    int sendTime = finishTime - startTime; 

    // Receive number of bytes read from server 
    int nReads; 
    cout << "reading nReads from server... " << endl; 
    read(clientSd, (void*)nReads, SIZEOFINT); 
    cout << "SUCCESS" << endl; 

    // Record read time 
    gettimeofday(&theTime, NULL); 
    int readTime = theTime.tv_usec + theTime.tv_sec * 1000000; 

    // Calculate the round-trip time 
    int roundTime = readTime - startTime; 

    // Display data sending statistics 
    cout << "Test " << testType << ": data-sending time = " << sendTime; 
    cout << " usec, round-trip time = " << roundTime << " usec, # reads = "; 
    cout << nReads << endl; 

    // Close the socket 
    cout << "Closing the socket... " << endl; 
    close(clientSd); 
    cout << "SUCCESS" << endl; 

    cout << "Exiting!" << endl; 
    return 0; 
} 

我已经花了大约14个小时对此进行了故障排除,并且在来这里之前尝试了许多事情:

  • 使用SIGTERM代替SIGIO
  • 重新安排操作的顺序,因此sigaction的设置之前接受传入的连接
  • 使用触发函数中的fcntl代替睡眠循环
  • 内使用场从传递到触发功能
  • 的siginfo_t结构使用sa_handler,而不是在所有
  • 设置SA_SIGINFO标志(所以siginfo_t不通过)
  • 不调用fcntl切换服务器描述符这些程序上
  • 运行的开关,这些程序所使用的睡眠循环

  • 调用一切都在这一点上我的教练告诉我使用已弃用信号的方法,而不是港口,而是似乎是一个不好的解决方案siginfo当然是目前常见的做法,使用它不应该是这么难吗?任何建议尝试将不胜感激!

  • +0

    您可能想要阅读'signal(7)'手册页。你应该学会更多关于多路复用系统调用,比如'poll(2)'(或者更老的'select(2)')。 –

    回答

    0

    通过用acceptSockAddr替换对newSockAddr的引用来解决。下面是当前的代码,现在在新的和可怕的方式!:故障

    server.cpp:

    #include <sys/types.h> // socket, bind 
    #include <sys/socket.h> // socket, bind, listen, inet_ntoa 
    #include <netinet/in.h> // htonl, htons, inet_ntoa 
    #include <arpa/inet.h> // inet_ntoa 
    #include <netdb.h>  // gethostbyname 
    #include <unistd.h>  // read, write, close 
    #include <string.h>  // bzero 
    #include <netinet/tcp.h> // SO_REUSEADDR 
    #include <sys/uio.h>  // writev 
    #include <signal.h>  // sigaction 
    #include <sys/time.h>  // gettimeofday 
    #include <unistd.h>  // write 
    #include <fcntl.h>  // fcntl 
    #include <iostream>  // cout 
    
    using namespace std; 
    #define BUFSIZE 1500 
    #define MAX_PENDING 5 
    #define SIZEOFINT 4 
    
    // Globals 
    int nreps; 
    int nbufs; 
    int newSd; 
    
    // Read all the data from the client and output how long it took 
    void readFromClient(int sig, siginfo_t *siginfo, void *context) 
    { 
        cout << "readFromClient triggered!" << endl; 
    
        // Declare data buffer 
        char databuf[BUFSIZE]; 
    
        // Record start time 
        struct timeval theTime; 
        gettimeofday(&theTime, NULL); 
        int startTime = theTime.tv_usec + theTime.tv_sec * 1000000; 
    
        // Keep reading until the buffer is full 
        int nRead = 0; 
        while((nRead += read(newSd, databuf, BUFSIZE - nRead)) < BUFSIZE) 
        { 
         cout << "nRead now: " << nRead << endl; 
        } 
    
        // For testing single byte read 
        /* 
        cout << "Reading a byte... " << endl; 
        char bytebuf[1]; 
        read(newSd, bytebuf, 1); 
        cout << "SUCCESS" << endl; 
        */ 
    
        // Record finish time 
        gettimeofday(&theTime, NULL); 
        int finishTime = theTime.tv_usec + theTime.tv_sec * 1000000; 
    
        // Calculate the receiving time 
        int receiveTime = finishTime - startTime; 
    
        // Display the receiving time 
        cout << "data-receiving time = " << receiveTime << " usec" << endl; 
    
        // Tell the client how much data was read 
        cout << "Writing amount read... " << endl; 
        write(newSd, (void*)nRead, SIZEOFINT); 
        cout << "SUCCESS" << endl; 
    
        // Close the socket 
        cout << "Closing socket... " << endl; 
        close(newSd); 
        cout << "SUCCESS" << endl; 
    } 
    
    int main(int argc, char *argv[]) 
    { 
        // Store command line arguments 
        int port = atoi(argv[1]); 
        int nreps = atoi(argv[2]); 
        int nbufs = atoi(argv[3]); 
    
        // Declare a socket 
        struct sockaddr_in acceptSockAddr; 
        socklen_t len = sizeof(acceptSockAddr); 
        memset((char*)&acceptSockAddr, '\0', sizeof(acceptSockAddr)); 
        acceptSockAddr.sin_family = AF_INET; // Address Family Internet 
        acceptSockAddr.sin_addr.s_addr = htonl(INADDR_ANY); 
        acceptSockAddr.sin_port = htons(port); // convert host byte-order 
    
        // Open a stream-oriented socket 
        int serverSd; 
        if((serverSd = socket(PF_INET, SOCK_STREAM, 0)) < 0) 
        { 
         perror("socket failure"); 
         exit(1); 
        } 
    
        // Signal OS to reuse this port once server closes 
        const int on = 1; 
        setsockopt(serverSd, SOL_SOCKET, SO_REUSEADDR, (char*)&on, sizeof(int)); 
    
        // Bind socket to local address 
        if(bind(serverSd, (sockaddr*)&acceptSockAddr, sizeof(acceptSockAddr)) < 0) 
        { 
         perror("bind failure"); 
         exit(1); 
        } 
    
        // Instruct OS to listen for up to 5 clients 
        listen(serverSd, MAX_PENDING); 
    
        // Set up signal handler for IO from client 
        struct sigaction action; 
        memset(&action, '\0', sizeof(action)); 
        action.sa_sigaction = &readFromClient; 
        action.sa_flags = SA_SIGINFO; 
        //fcntl(newSd, F_SETSIG, SIGIO); // Fixes problem with si_fd 
        if(sigaction(SIGIO, &action, NULL) < 0) 
        { 
         perror("sigaction"); 
         exit(1); 
        } 
    
        while(1) // sleep forever 
        { 
         cout << "Waiting for client... " << endl; 
         if((newSd = accept(serverSd, (struct sockaddr*)&acceptSockAddr, &len)) < 0) 
         { 
          perror("accept failure"); 
          //exit(1); 
         } 
         cout << "SUCCESS" << endl; 
         fcntl(newSd, F_SETOWN, getpid()); 
         fcntl(newSd, F_SETFL, FASYNC); 
        } 
        return 0; 
    } 
    

    client.cpp:

    #include <sys/types.h> // socket, bind 
    #include <sys/socket.h> // socket, bind, listen, inet_ntoa 
    #include <netinet/in.h> // htonl, htons, inet_ntoa 
    #include <arpa/inet.h> // inet_ntoa 
    #include <netdb.h>  // gethostbyname 
    #include <unistd.h>  // read, write, close 
    #include <string.h>  // bzero 
    #include <netinet/tcp.h> // SO_REUSEADDR 
    #include <sys/uio.h>  // writev 
    #include <signal.h>  // sigaction 
    #include <sys/time.h>  // gettimeofday 
    #include <fcntl.h>  // fcntl 
    #include <iostream>  // cout 
    
    using namespace std; 
    #define BUFSIZE 1500 
    #define SIZEOFINT 4 
    
    int main(int argc, char *argv[]) 
    { 
        // Store commmand line arguments 
        int server_port = atoi(argv[1]); 
        int nreps = atoi(argv[2]); 
        int nbufs = atoi(argv[3]); 
        int bufsize = atoi(argv[4]); 
        const char* server_name = argv[5]; 
        int testType = atoi(argv[6]); 
    
        // Check to ensure proper buffer count/sizes 
        if(nbufs * bufsize != BUFSIZE) 
        { 
         perror("nbufs times bufsize must equal BUFSIZE"); 
         exit(1); 
        } 
    
        if(testType < 1 || testType > 3) 
        { 
         perror("test type must be 1, 2, or 3"); 
         exit(1); 
        } 
    
        // Create buffers 
        char databuf[nbufs][bufsize]; 
    
        // Retrieve hostent structure 
        struct hostent* host = gethostbyname(server_name); 
        if(!host) 
        { 
         perror("unknown hostname"); 
         exit(1); 
        } 
    
        // Declare socket structure 
        sockaddr_in sendSockAddr; 
        memset((char*)&sendSockAddr, '\0', sizeof(sendSockAddr)); 
        sendSockAddr.sin_family = AF_INET; // Address Family Internet 
        sendSockAddr.sin_addr.s_addr = inet_addr(inet_ntoa(*(struct in_addr*)*host->h_addr_list)); 
        sendSockAddr.sin_port = htons(server_port); // convert host byte-order 
    
        // Open stream-oriented socket 
        int clientSd; 
        if((clientSd = socket(PF_INET, SOCK_STREAM, 0)) < 0) 
        { 
         perror("socket failure"); 
         exit(1); 
        }; 
    
        // Connect socket to server 
        if(connect(clientSd, (struct sockaddr*)&sendSockAddr, sizeof(sendSockAddr)) < 0) 
        { 
         perror("connect failure"); 
         exit(1); 
        }; 
    
        // Record start time 
        struct timeval theTime; 
        gettimeofday(&theTime, NULL); 
        int startTime = theTime.tv_usec + theTime.tv_sec * 1000000; 
    
        // Conduct tests 
        for(int i = 0; i < nreps; i++) 
        { 
         switch(testType) 
         { 
          case 1: 
          { 
           // Multiple write test 
           cout << "Running multiple write test" << endl; 
           for(int j = 0; j < nbufs; j++) 
           { 
            cout << "Writing buffer " << j << "... " << endl; 
            write(clientSd, databuf[j], bufsize); 
            cout << "SUCCESS" << endl; 
           } 
           cout << "Finished multiple write test" << endl; 
          } 
          case 2: 
          { 
           // Vector write test 
           cout << "Running vector write test" << endl; 
           struct iovec vector[nbufs]; 
           for(int j = 0; j < nbufs; j++) 
           { 
            vector[j].iov_base = databuf[j]; 
            vector[j].iov_len = bufsize; 
           } 
           cout << "Writing vector... " << endl; 
           writev(clientSd, vector, nbufs); 
           cout << "SUCCESS" << endl; 
           cout << "Finished vector write test" << endl; 
          } 
          case 3: 
          { 
           // Single write test 
           cout << "Running single write test" << endl; 
    
           cout << "Writing... "; 
           write(clientSd, databuf, nbufs * bufsize); 
           cout << "SUCCESS" << endl; 
    
           // For testing single byte write 
           /* 
           cout << "writing a byte..." << endl; 
           char singleByte[1]; 
           write(clientSd, singleByte, 1); 
           cout << "wrote a byte!" << endl; 
           */ 
    
           cout << "Finished single write test" << endl; 
          } 
         } 
        } 
    
        // Record finish time 
        gettimeofday(&theTime, NULL); 
        int finishTime = theTime.tv_usec + theTime.tv_sec * 1000000; 
    
        // Calculate the sending time 
        int sendTime = finishTime - startTime; 
    
        // Receive number of bytes read from server 
        int nReads = 0; 
        cout << "reading nReads from server... " << endl; 
        read(clientSd, (void*)nReads, SIZEOFINT); 
        cout << "SUCCESS" << endl; 
    
        // Record read time 
        gettimeofday(&theTime, NULL); 
        int readTime = theTime.tv_usec + theTime.tv_sec * 1000000; 
    
        // Calculate the round-trip time 
        int roundTime = readTime - startTime; 
    
        // Display data sending statistics 
        cout << "Test " << testType << ": data-sending time = " << sendTime; 
        cout << " usec, round-trip time = " << roundTime << " usec, # reads = "; 
        cout << nReads << endl; 
    
        // Close the socket 
        cout << "Closing the socket... " << endl; 
        close(clientSd); 
        cout << "SUCCESS" << endl; 
    
        cout << "Exiting!" << endl; 
        return 0; 
    } 
    

    依然存在着严重问题,试图建立时在关闭第一个客户端后连接到服务器的第二个客户端。

    2

    您似乎没有将F_SETOWN套接字当作控制进程并SETFL O_ASYNC标志,这会导致套接字实际向SETOWN'd进程组发送信号。如果你不做这些事情,不管你使用signal(2)还是sigaction(2),都不会发送信号。

    +0

    我以为我在睡眠循环内部这样做? –