2013-05-14 53 views
0

我真的不明白这里出了什么问题,所以我希望有人会发现我错过的东西。套接字在HPUX上没有收到完整的数据

我正在写一个用户守护进程,它接受我在java中开发的客户端。目前此客户端只连接并发送用户名密码。我开发了cygwin下的代码,它在那里工作。守护进程发送它的介绍,然后客户端发送用户名和密码,守护进程响应断开客户端或发送确定(尚未完成)。

当我使用cygwin测试它时,它在localhost上工作。我将代码移植到HPUX,客户端可以连接并从守护进程接收引入。现在,当客户端发送它的用户名和密码时,它不再起作用。守护进程只接收一个字节,当它试图再次读取时,我得到-1作为EAGAIN的结果,没有别的。客户端不显示任何错误,并且在守护程序端也没有。当我用gdb执行代码时,消息完全恢复。 :(

,我用的是这样的代码,如果需要更多的信息,我可以添加:

int TCPSocket::receive(SocketMessage &oMessage, int nBytes) 
{ 
    int max = getSendBufferSize(); 

    if(nBytes != -1 && nBytes < max) 
     max = nBytes; 

    SocketMessage sb(max); 
    int rcv_bytes = 0; 
    int total = 0; 
    int error = 0; 

    while(1) 
    { 
     rcv_bytes = ::recv(getSocketId(), &sb[0], sb.size(), 0); 
     error = errno; 
     FILE_LOG(logDEBUG4) << "Received on socket: " << mSocketId << " bytes: " << rcv_bytes << " expected:" << sb.size() << " total: " << total << " errno: " << error; 

     if(rcv_bytes == -1) 
     { 
      if(error == EAGAIN || error == EWOULDBLOCK) 
       return total; 

      throw SocketException(this, SocketException::RECEIVE, error, "Socket", "Client connection error!", __FILE__, __LINE__); 
     } 

     //if(rcv_bytes == 0) 
     // throw SocketException(this, SocketException::RECEIVE, error, "Socket", "Client connection has been closed!"); 

     total += rcv_bytes; 
     oMessage.insert(oMessage.end(), sb.begin(), sb.begin()+rcv_bytes); 
    } 

    return total; 
} 

日志的输出是这样的:

16:16:04.391 DEBUG4: Received on socket: 4 bytes: 1 expected:32768 total: 0 errno: 2 
16:16:04.391 DEBUG4: Received on socket: 4 bytes: -1 expected:32768 total: 1 errno: 11 

那么,是在30个字节的休息,为什么不回来了?

UPDATE

这只是实际接收数据的代码的一部分。套接字类本身只处理没有任何协议的原始套接字。该协议在一个单独的类中实现。这个接收函数应该获取网络上可用的字节数,并将其放入缓冲区(SocketMessage)。不管是字节数是多个消息还是只有一个消息的一部分,因为控制类将构建(可能)部分消息流中的实际消息块。因此,第一次调用只接收一个字节不是问题,因为如果消息未完成,调用程序将一直等待,直到更多数据到达并且消息完成。因为可以有多个客户端使用非阻塞套接字。我不想处理单独的线程,所以我的服务器复用了连接。 这里的问题是,接收只接收一个字节,而我知道应该有更多。处理错误代码EAGAIN,并在接下来输入接收时,它应该得到更多的字节。即使网络只传输一个字节,其余的信息仍然会到达下一个,但事实并非如此。在socket上等待接收数据块的select,就好像这里没有任何东西。当我在dbg中运行相同的代码并逐步完成工作。 当我再次连接到同一个客户端时,突然更多的字节被恢复。 当我使用本地代码与cygwin相同的代码,它工作正常。

UPDATE

下面是完整的代码。

Main.cpp 

    mServerSocket = new TCPSocket(getListeningPort()); 
    mServerSocket->bindSocket(); 
    mServerSocket->setSocketBlocking(false); 
    mServerSocket->listenToClient(0); 

    setupSignals(); 
    while(isSIGTERM() == false) 
    { 
     try 
     { 
      max = prepareListening(); 

      //memset(&ts, 0, sizeof(struct timespec)); 
      pret = pselect(max+1, &mReaders, &mWriters, &mExceptions, NULL, &mSignalMask); 
      error_code = errno; 
      if(pret == 0) 
      { 
       // Timeout occured, but we are not interested in that for now. 
       // Currently this shouldn't happen anyway. 
       continue; 
      } 
      processRequest(pret, error_code); 

     } 
     catch (SocketException &excp) 
     { 
      removeClientConnection(findClientConnection(excp.getTCPSocket())); 
     } 
    } // while sigTERM 


BaseSocket.cpp: 

#ifdef UNIX 

    #include <sys/socket.h> 
    #include <sys/types.h> 
    #include <sys/ioctl.h> 
    #include <unistd.h> 
    #include <fcntl.h> 
    #include <errno.h> 

#endif 

#include "support/exceptions/socket_exception.h" 
#include "support/logging/simple_log.h" 
#include "support/network/base_socket.h" 

using namespace std; 

BaseSocket::BaseSocket(void) 
{ 
    mSocketId = -1; 
    mSendBufferSize = MAX_SEND_LEN; 
} 

BaseSocket::BaseSocket(int pNumber) 
{ 
    mSocketId = -1; 
    mPortNumber = pNumber; 
    mBlocking = 1; 
    mSendBufferSize = MAX_SEND_LEN; 

    try 
    { 
     if ((mSocketId = ::socket(AF_INET, SOCK_STREAM, 0)) == -1) 
     { 
#ifdef UNIX 
      throw SocketException(this, SocketException::CONSTRUCTOR, errno, "Socket", "unix: error in socket constructor", __FILE__, __LINE__); 
#endif 
     } 
    } 
    catch (SocketException& excp) 
    { 
     excp.response(); 
    } 

    /* 
    set the initial address of client that shall be communicated with to 
    any address as long as they are using the same port number. 
    The clientAddr structure is used in the future for storing the actual 
    address of client applications with which communication is going 
    to start 
    */ 
    mClientAddr.sin_family = AF_INET; 
    mClientAddr.sin_addr.s_addr = htonl(INADDR_ANY); 
    mClientAddr.sin_port = htons(mPortNumber); 
    updateSendBufferSize(MAX_SEND_LEN); 
} 

void BaseSocket::updateSendBufferSize(int nNewSize) 
{ 
    mSendBufferSize = getSendBufferSize(); 
    if(mSendBufferSize > nNewSize) 
     mSendBufferSize = nNewSize; 
} 

BaseSocket::~BaseSocket(void) 
{ 
    close(); 
} 

void BaseSocket::setSocketId(int socketFd) 
{ 
    mSocketId = socketFd; 
} 

int BaseSocket::getSocketId() 
{ 
    return mSocketId; 
} 

// returns the port number 
int BaseSocket::getPortNumber() 
{ 
    return mPortNumber; 
} 

void BaseSocket::setDebug(int debugToggle) 
{ 
    try 
    { 
     if (setsockopt(mSocketId, SOL_SOCKET, SO_DEBUG, (char *) &debugToggle, sizeof(debugToggle)) == -1) 
     { 
#ifdef UNIX 
      throw SocketException(this, SocketException::OPTION, errno, "Socket", "unix: error set debug", __FILE__, __LINE__); 
#endif 
     } 
    } 
    catch (SocketException& excp) 
    { 
     excp.response(); 
    } 
} 

void BaseSocket::setReuseAddr(int reuseToggle) 
{ 
    try 
    { 
     if (setsockopt(mSocketId, SOL_SOCKET, SO_REUSEADDR, (char *) &reuseToggle, 
       sizeof(reuseToggle)) == -1) 
     { 
#ifdef UNIX 
      throw SocketException(this, SocketException::OPTION, errno, "Socket", "unix: error set reuse address", __FILE__, __LINE__); 
#endif 
     } 
    } 
    catch (SocketException& excp) 
    { 
     excp.response(); 
    } 
} 

void BaseSocket::setKeepAlive(int aliveToggle) 
{ 
    try 
    { 
     if (setsockopt(mSocketId, SOL_SOCKET, SO_KEEPALIVE, (char *) &aliveToggle, 
       sizeof(aliveToggle)) == -1) 
     { 
#ifdef UNIX 
      throw SocketException(this, SocketException::OPTION, errno, "Socket", "unix: error set keep alive", __FILE__, __LINE__); 
#endif 
     } 
    } 
    catch (SocketException& excp) 
    { 
     excp.response(); 
    } 
} 

void BaseSocket::setLingerSeconds(int seconds) 
{ 
    struct linger lingerOption; 

    if (seconds > 0) 
    { 
     lingerOption.l_linger = seconds; 
     lingerOption.l_onoff = 1; 
    } 
    else 
     lingerOption.l_onoff = 0; 

    try 
    { 
     if (setsockopt(mSocketId, SOL_SOCKET, SO_LINGER, (char *) &lingerOption, 
       sizeof(struct linger)) == -1) 
     { 
#ifdef UNIX 
      throw SocketException(this, SocketException::OPTION, errno, "Socket", "unix: error set linger seconds", __FILE__, __LINE__); 
#endif 
     } 
    } 
    catch (SocketException& excp) 
    { 
     excp.response(); 
    } 
} 

void BaseSocket::setLingerOnOff(bool lingerOn) 
{ 
    struct linger lingerOption; 

    if (lingerOn) 
     lingerOption.l_onoff = 1; 
    else 
     lingerOption.l_onoff = 0; 

    try 
    { 
     if (setsockopt(mSocketId, SOL_SOCKET, SO_LINGER, (char *) &lingerOption, 
       sizeof(struct linger)) == -1) 
     { 
#ifdef UNIX 
      throw SocketException(this, SocketException::OPTION, errno, "Socket", "unix: error set linger on/off", __FILE__, __LINE__); 
#endif 
     } 
    } 
    catch (SocketException& excp) 
    { 
     excp.response(); 
    } 
} 

void BaseSocket::setSendBufferSize(int sendBufSize) 
{ 
    if (setsockopt(mSocketId, SOL_SOCKET, SO_SNDBUF, (char *) &sendBufSize, sizeof(sendBufSize)) == -1) 
    { 
#ifdef UNIX 
     throw SocketException(this, SocketException::OPTION, errno, "Socket", "unix: error send buffer size", __FILE__, __LINE__); 
#endif 
    } 
    updateSendBufferSize(sendBufSize); 
} 

void BaseSocket::setReceiveBufferSize(int receiveBufSize) 
{ 
    if (setsockopt(mSocketId, SOL_SOCKET, SO_RCVBUF, (char *) &receiveBufSize, sizeof(receiveBufSize)) == -1) 
    { 
#ifdef UNIX 
     throw SocketException(this, SocketException::OPTION, errno, "Socket", "unix: error set receive buffer size", __FILE__, __LINE__); 
#endif 
    } 
} 

int BaseSocket::isSocketBlocking() 
{ 
    return mBlocking; 
} 

void BaseSocket::setSocketBlocking(int blockingToggle) 
{ 
    if (blockingToggle) 
    { 
     if (isSocketBlocking()) 
      return; 
     else 
      mBlocking = 1; 
    } 
    else 
    { 
     if (!isSocketBlocking()) 
      return; 
     else 
      mBlocking = 0; 
    } 

    try 
    { 
#ifdef UNIX 
     int flags; 
     if (-1 == (flags = fcntl(mSocketId, F_GETFL, 0))) 
      flags = 0; 

     if(mBlocking) 
      fcntl(mSocketId, F_SETFL, flags & (~O_NONBLOCK)); 
     else 
      fcntl(mSocketId, F_SETFL, flags | O_NONBLOCK); 

     /*if (ioctl(socketId, FIONBIO, (char *) &blocking) == -1) 
     { 
      throw SocketException(this, SocketException::OPTION, errno, "Socket", "unix: error set socke blocking"); 
     }*/ 
#endif 
    } 
    catch (SocketException& excp) 
    { 
     excp.response(); 
    } 
} 

int BaseSocket::getDebug() 
{ 
    int myOption; 
    int myOptionLen = sizeof(myOption); 

    try 
    { 
     if (getsockopt(mSocketId, SOL_SOCKET, SO_DEBUG, (void *) &myOption, &myOptionLen) == -1) 
     { 
#ifdef UNIX 
      throw SocketException(this, SocketException::OPTION, errno, "Socket", "unix: error get debug", __FILE__, __LINE__); 
#endif 
     } 
    } 
    catch (SocketException& excp) 
    { 
     excp.response(); 
     return -1; 
    } 

    return myOption; 
} 

int BaseSocket::getReuseAddr() 
{ 
    int myOption; 
    int myOptionLen = sizeof(myOption); 

    try 
    { 
     if (getsockopt(mSocketId, SOL_SOCKET, SO_REUSEADDR, (void *) &myOption, &myOptionLen) == -1) 
     { 
#ifdef UNIX 
      throw SocketException(this, SocketException::OPTION, errno, "Socket", "unix: error get reuse address", __FILE__, __LINE__); 
#endif 
     } 
    } 
    catch (SocketException& excp) 
    { 
     excp.response(); 
     return -1; 
    } 

    return myOption; 
} 

int BaseSocket::getKeepAlive() 
{ 
    int myOption; 
    int myOptionLen = sizeof(myOption); 

    try 
    { 
     if (getsockopt(mSocketId, SOL_SOCKET, SO_KEEPALIVE, (void *) &myOption, &myOptionLen) == -1) 
     { 
#ifdef UNIX 
      throw SocketException(this, SocketException::OPTION, errno, "Socket", "unix: error get keep alive", __FILE__, __LINE__); 
#endif 
     } 
    } 
    catch (SocketException& excp) 
    { 
     excp.response(); 
     return -1; 
    } 
    return myOption; 
} 

int BaseSocket::getLingerSeconds() 
{ 
    struct linger lingerOption; 
    int myOptionLen = sizeof(struct linger); 

    try 
    { 
     if (getsockopt(mSocketId, SOL_SOCKET, SO_LINGER, (void *) &lingerOption, &myOptionLen) == -1) 
     { 
#ifdef UNIX 
      throw SocketException(this, SocketException::OPTION, errno, "Socket", "unix: error get linger seconds", __FILE__, __LINE__); 
#endif 
     } 
    } 
    catch (SocketException& excp) 
    { 
     excp.response(); 
     return -1; 
    } 

    return lingerOption.l_linger; 
} 

bool BaseSocket::getLingerOnOff() 
{ 
    struct linger lingerOption; 
    int myOptionLen = sizeof(struct linger); 

    try 
    { 
     if (getsockopt(mSocketId, SOL_SOCKET, SO_LINGER, (void *) &lingerOption, &myOptionLen) == -1) 
     { 
#ifdef UNIX 
      throw SocketException(this, SocketException::OPTION, errno, "Socket", "unix: error get linger on/off", __FILE__, __LINE__); 
#endif 
     } 
    } 
    catch (SocketException& excp) 
    { 
     excp.response(); 
    } 

    if (lingerOption.l_onoff == 1) 
     return true; 
    else 
     return false; 
} 

int BaseSocket::getSendBufferSize() 
{ 
    int sendBuf; 
    int myOptionLen = sizeof(sendBuf); 

    try 
    { 
     if (getsockopt(mSocketId, SOL_SOCKET, SO_SNDBUF, (void *)&sendBuf, &myOptionLen) == -1) 
     { 
#ifdef UNIX 
      throw SocketException(this, SocketException::OPTION, errno, "Socket", "unix: error get send buffer size", __FILE__, __LINE__); 
#endif 
     } 
    } 
    catch (SocketException& excp) 
    { 
     excp.response(); 
     return -1; 
    } 
    return sendBuf; 
} 

int BaseSocket::getReceiveBufferSize() 
{ 
    int rcvBuf; 
    int myOptionLen = sizeof(rcvBuf); 

    try 
    { 
     if (getsockopt(mSocketId, SOL_SOCKET, SO_RCVBUF, (void *) &rcvBuf, &myOptionLen) == -1) 
     { 
#ifdef UNIX 
      throw SocketException(this, SocketException::OPTION, errno, "Socket", "unix: error get receive buffer size", __FILE__, __LINE__); 
#endif 
     } 
    } 
    catch (SocketException& excp) 
    { 
     excp.response(); 
     return -1; 
    } 
    return rcvBuf; 
} 

ostream &operator<<(ostream& io, BaseSocket& s) 
{ 
    string flagStr = ""; 

    io << endl; 
    io << "Summary of socket settings:" << endl; 
    io << " Socket Id:  " << s.getSocketId() << endl; 
    io << " port #:  " << s.getPortNumber() << endl; 
    io << " debug:   " << (flagStr = s.getDebug() ? "true" : "false") 
      << endl; 
    io << " reuse addr: " << (flagStr = s.getReuseAddr() ? "true" : "false") 
      << endl; 
    io << " keep alive: " << (flagStr = s.getKeepAlive() ? "true" : "false") 
      << endl; 
    io << " send buf size: " << s.getSendBufferSize() << endl; 
    io << " recv bug size: " << s.getReceiveBufferSize() << endl; 
    io << " blocking:  " 
      << (flagStr = s.isSocketBlocking() ? "true" : "false") << endl; 
    io << " linger on:  " 
      << (flagStr = s.getLingerOnOff() ? "true" : "false") << endl; 
    io << " linger seconds: " << s.getLingerSeconds() << endl; 
    io << endl; 
    return io; 
} 

void BaseSocket::close(void) 
{ 
    ::close(mSocketId); 
} 

TCPSocket.cpp: 


#ifdef UNIX 
    #include <sys/socket.h> 
    #include <sys/types.h> 
    #include <sys/ioctl.h> 
    #include <unistd.h> 
    #include <fcntl.h> 
    #include <errno.h> 
#endif 

#include <sstream> 

#include "support/logging/log.h" 
#include "support/exceptions/socket_exception.h" 
#include "support/logging/simple_log.h" 
#include "support/network/tcp_socket.h" 

using namespace std; 

const int MSG_HEADER_LEN = 6; 

TCPSocket::TCPSocket() 
: BaseSocket() 
{ 
} 

TCPSocket::TCPSocket(int portId) 
: BaseSocket(portId) 
{ 
} 

TCPSocket::~TCPSocket() 
{ 
} 

void TCPSocket::initialize() 
{ 
} 

void TCPSocket::bindSocket() 
{ 
    try 
    { 
     if (bind(mSocketId, (struct sockaddr *) &mClientAddr, sizeof(struct sockaddr_in)) == -1) 
     { 
#ifdef UNIX 
      throw SocketException(this, SocketException::BIND, 0, "Socket", "unix: error calling bind()", __FILE__, __LINE__); 
#endif 
     } 
    } 
    catch (SocketException& excp) 
    { 
     excp.response(); 
    } 
} 

void TCPSocket::connectToServer(string& serverNameOrAddr, hostType hType) 
{ 
    /* 
    when this method is called, a client socket has been built already, 
    so we have the socketId and portNumber ready. 

    a HostInfo instance is created, no matter how the server's name is 
    given (such as www.yuchen.net) or the server's address is given (such 
    as 169.56.32.35), we can use this HostInfo instance to get the 
    IP address of the server 
    */ 

    HostInfo serverInfo(serverNameOrAddr, hType); 

    // Store the IP address and socket port number 
    struct sockaddr_in serverAddress; 

    serverAddress.sin_family = AF_INET; 
    serverAddress.sin_addr.s_addr = inet_addr(
      serverInfo.getHostIPAddress().c_str()); 
    serverAddress.sin_port = htons(mPortNumber); 

    // Connect to the given address 
    try 
    { 
     if (connect(mSocketId, (struct sockaddr *) &serverAddress, sizeof(serverAddress)) == -1) 
     { 
#ifdef UNIX 
      throw SocketException(this, SocketException::CONNECT, 0, "Socket", "unix: error calling connect()", __FILE__, __LINE__); 
#endif 
     } 
    } 
    catch (SocketException& excp) 
    { 
     excp.response(); 
    } 
} 

TCPSocket *TCPSocket::acceptClient(string& clientHost) 
{ 
    int newSocket; // the new socket file descriptor returned by the accept system call 

    // the length of the client's address 
    int clientAddressLen = sizeof(struct sockaddr_in); 
    struct sockaddr_in clientAddress; // Address of the client that sent data 

    // Accepts a new client connection and stores its socket file descriptor 
    try 
    { 
     if ((newSocket = accept(mSocketId, (struct sockaddr *) &clientAddress, &clientAddressLen)) == -1) 
     { 
#ifdef UNIX 
      throw SocketException(this, SocketException::ACCEPT, 0, "Socket", "unix: error calling accept()", __FILE__, __LINE__); 
#endif 
     } 
    } 
    catch (SocketException& excp) 
    { 
     excp.response(); 
     return NULL; 
    } 

    // Get the host name given the address 
    char *sAddress = inet_ntoa((struct in_addr) clientAddress.sin_addr); 
    HostInfo clientInfo(sAddress, ADDRESS); 
    clientHost += clientInfo.getHostName(); 

    // Create and return the new TCPSocket object 
    TCPSocket* retSocket = new TCPSocket(); 
    retSocket->setSocketId(newSocket); 
    return retSocket; 
} 

void TCPSocket::listenToClient(int totalNumPorts) 
{ 
    try 
    { 
     if (listen(mSocketId, totalNumPorts) == -1) 
     { 
#ifdef UNIX 
      throw SocketException(this, SocketException::LISTEN, 0, "Socket", "unix: error calling listen()", __FILE__, __LINE__); 
#endif 
     } 
    } 
    catch (SocketException& excp) 
    { 
     excp.response(); 
    } 
} 

ostream &operator<<(ostream &oStream, const TCPSocket &oSocket) 
{ 
    oStream << oSocket.mSocketId; 
    return oStream; 
} 

int TCPSocket::send(SocketMessage const &oBuffer, int nSize) 
{ 
    int numBytes; // the number of bytes sent 
    int error = errno; 

    if(nSize == -1) 
     nSize = oBuffer.size(); 

    if((unsigned int)nSize > oBuffer.size()) 
    { 
     std::stringstream ss; 
     ss << "Invalid Buffersize! Requested: " << (unsigned int)nSize << " Provided: " << oBuffer.size(); 
     std::string s; 
     ss >> s; 
     FILE_LOG(logERROR) << s; 
     throw SocketException(this, SocketException::SEND, 0, "Socket", s, __FILE__, __LINE__); 
    } 

    // Sends the message to the connected host 
    try 
    { 
     FILE_LOG(logDEBUG4) << "Sending on socket: "<< mSocketId << " bytes:" << nSize; 
     numBytes = ::send(mSocketId, &oBuffer[0], nSize, 0); 
     error = errno; 
     FILE_LOG(logDEBUG4) << "Sent on socket: "<< mSocketId << " bytes:" << nSize << " errno: " << error; 
     if(numBytes == -1) 
     { 
#ifdef UNIX 
      if(error == EAGAIN || error == EWOULDBLOCK) 
      { 
       return -1; 
      } 
      else 
       throw SocketException(this, SocketException::SEND, error, "Socket", "unix: error calling send()", __FILE__, __LINE__); 
#endif 
     } 
    } 
    catch (SocketException& excp) 
    { 
     excp.response(); 
    } 

    return numBytes; 
} 

int TCPSocket::receive(SocketMessage &oMessage, int nBytes) 
{ 
    int max = getSendBufferSize(); 

    if(nBytes != -1 && nBytes < max) 
     max = nBytes; 

    SocketMessage sb(max); 
    int rcv_bytes = 0; 
    int total = 0; 
    int error = 0; 

    while(1) 
    { 
     rcv_bytes = ::recv(getSocketId(), &sb[0], sb.size(), 0); 
     error = errno; 
     FILE_LOG(logDEBUG4) << "Received on socket: " << getSocketId() << " bytes: " << rcv_bytes << " expected:" << sb.size() << " total: " << total << " errno: " << error; 

     if(rcv_bytes == -1) 
     { 
      if(error == EAGAIN || error == EWOULDBLOCK) 
       return total; 

      throw SocketException(this, SocketException::RECEIVE, error, "Socket", "Client connection error!", __FILE__, __LINE__); 
     } 

     // Socket has been closed. 
     if(rcv_bytes == 0) 
      return total; 

     total += rcv_bytes; 
     oMessage.insert(oMessage.end(), sb.begin(), sb.begin()+rcv_bytes); 
    } 

    return total; 
} 

void TCPSocket::close(void) 
{ 
    BaseSocket::close(); 
} 
+1

psst,那不是c – 2013-05-14 14:28:22

+0

问题是关于底层的C函数,即在套接字上接收,而不是关于C++特性。 – Devolus 2013-05-14 14:30:16

+0

当然,但如果将其标记为C++,则可以获得更多帮助。 – 2013-05-14 14:32:06

回答

1

你确定Nagle Algorithm没有在这里踢吗?如果您尚未通过设置TCP_NODELAY插座选项来禁用它,则可能不会发送数据,直到获得一定数量的数据(MSS)。

+0

明天我会看看这个。这将是一个暗示,可以解释我观察到的情况。也许本地主机上的beahviour不同?在客户端上,我现在使用一个没有任何特定选项的Java套接字。 – Devolus 2013-05-14 17:47:01

+0

如果是这种情况,缓冲区是否应该在某个时候传输?或者套接字是否可以刷新? – Devolus 2013-05-14 17:59:27

+0

Thnaks这个指针。这种情况似乎有所不同,因为当我设置TCP_NODELAY或发送更大的字符串时,它就可以工作。但我不明白的是,当我读到这个消息时,我会预期消息的其余部分应该延迟显示,但事实并非如此。即使我通过fcntl将其设置为非阻塞,或者在每次进入rcv之前都必须执行此操作,我的recv呼叫会在一段时间后阻止吗? – Devolus 2013-05-15 08:25:23

-1

任何一次调用recv返回的字节数都是不可预知的。许多消息都是以多个部分接收的,因此如果您还没有收到完整的消息,则需要再次调用recv。但是你的代码似乎没有办法确定是否收到整个消息。并且,您的代码在EWOULDBLOCK上返回,但EWOULDBLOCK是套接字操作的正常部分。它不表示错误或消息的完成。

+0

这段代码应该只接收那么多。实际的消息是由调用者构造的。查看我的更新。问题是没有更多的数据到达。当我使用本地代码和cygwin使用相同的代码时,它工作正常。 – Devolus 2013-05-14 16:51:08

+0

如果没有其他代码 - 调用'fcntl'和你使用'select'的方式 - 你不知道你做错了什么。你做错了什么。许多人已经成功编写了基于套接字的应用程序以用于HPUX系统。 – 2013-05-14 17:13:07

+0

问题是代码很大,所以我不知道我是否可以在这里发布。我确定问题出在我的代码中,但是在哪里? :) – Devolus 2013-05-14 17:16:50

0

第一个问题:
- 为什么使用非阻塞I/O?
- 你显然知道这个消息应该是30个字节长,那么你为什么要求32768个字节?

如果您使用的是非阻塞I/O,那么套接字的数量要比调用recv多得多。通过阻止I/O,每个错误都是一个真正的错误。使用非阻塞I/O时,您必须处理那个讨厌的EAGAIN/EWOULDBLOCK错误。恢复是可能的,但是当您将设备配置为使用非阻塞I/O时,您将负责恢复。

正如第一个名字(EAGAIN)所示,得到这个错误的结果意味着你需要再试一次,最好是等一下之后。一个简单但不是很好的等待方式是在sleep(或usleepnanosleep)一段时间。问题在于你可能等了太久,或者不够长。等待时间过长,系统可能无法响应,否则发件人可能会消失。等待太少,你正在使计算机在特权模式和非特权模式之间发生颠簸。

等待此类事件的最佳方式是使用基于事件的方案,但不幸的是这些方案不可移植。便携式方案是使用selectpoll。您可以使selectpoll无限期等待,也可以指定超时。我发现poll更容易使用,特别是当只涉及一个文件描述符时。不过这是个人偏好。其他人发现select更易于使用。

+0

我更新了关于协议1的问题。我正在使用pselect来处理更多的客户端。目前它只是一个,因为我在开发中,但守护进程应该处理一个任意(但很小)的数字。 – Devolus 2013-05-14 16:50:09

相关问题