c++ - Socket doesn't receive complete data on HPUX -
i don't understand going wrong here, hope may spot missed.
i'm writing user daemon accepting client develop in java. client connects , sends username password. developed code under cygwin , there works. daemon sends introduction, client sends username , password , daemon responds either disconnecting client or sending ok (not yet done).
when test using cygwin works on localhost. ported code hpux , client can connect , receives introduction daemon. when client sends it's username , password doesn't work anymore. daemon receives 1 byte , when tries read again -1 result eagain , nothing else. client doesn't show error , on daemon side there none. when step through code gdb messages revceived completely. :(
the code use this, if more info needed can add it:
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; }
the output of log this:
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
so rest of 30 bytes , why not returned?
update
this part of code receives data. socket class deals raw socket without protocoll. protocol implemented in separate class. receive function supposed grab many bytes there available on network , put in buffer (socketmessage). doesn't matter if number of bytes multiple messages or part of single message, because controlling class construct actual messageblock out of (maybe) partial messagestream. first call receives 1 byte not problem, because if message not complete caller waits in loop until more data arrives , message becomes completed. since there can more 1 client i'm using non blocking sockets. didn't want deal separate threads, server multiplexing connections. problem here receive receives 1 byte while know there should more. errorcode eagain handled , when receive entered next, should more bytes. if network transmitted 1 byte, rest of message should still arrive next, doesn't. select waits on socket receive data blocks if there nothing there. when run same code in dbg , step through works. when connect again same client more bytes revceived. when use same code cygwin using localhost works fine.
update
here complete code.
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, not interested in now. // 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 initial address of client shall communicated address long using same port number. clientaddr structure used in future storing actual address of client applications communication going 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 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 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 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 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 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 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 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 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 method called, client socket has been built already, have socketid , portnumber ready. hostinfo instance created, no matter how server's name given (such www.yuchen.net) or server's address given (such 169.56.32.35), can use hostinfo instance ip address of server */ hostinfo serverinfo(servernameoraddr, htype); // store ip address , 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 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; // new socket file descriptor returned accept system call // length of client's address int clientaddresslen = sizeof(struct sockaddr_in); struct sockaddr_in clientaddress; // address of client sent data // accepts new client connection , stores 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; } // host name given address char *saddress = inet_ntoa((struct in_addr) clientaddress.sin_addr); hostinfo clientinfo(saddress, address); clienthost += clientinfo.gethostname(); // create , return 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; // 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 message 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(); }
are sure nagle algorithm isn't kicking in here? if haven't disabled setting tcp_nodelay socket option data may not sent until amount of data (mss) available.
Comments
Post a Comment