⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tcpsocket.c

📁 robocup rcssmonitor-11.1.1.zip
💻 C
字号:
/* * Copyright (c) 1999 - 2001, Artur Merke <amerke@ira.uka.de>  * * This code is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * It is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * *//* author: Artur Merke */#include "tcpsocket.h"#include <iostream>#include <sys/types.h>#include <sys/socket.h>#include <cstring>#include <unistd.h>#include <arpa/inet.h>#include <netdb.h>#include <cerrno>#include <fcntl.h>#ifndef ERROR_STREAM#define ERROR_STREAM std::cerr#endif#ifndef ERROR_OUT#define ERROR_OUT ERROR_STREAM << "\n\n*** ERROR file=\"" << __FILE__ << "\" line=" << __LINE__#endif#ifndef WARNING_STREAM#define WARNING_STREAM std::cerr#endif#ifndef WARNING_OUT#define WARNING_OUT WARNING_STREAM << "\n\n*** WARNING file=\"" << __FILE__ << "\" line=" << __LINE__#endif/******************************************************************************/bool TCPsocket::send_msg(const char * buf, int len) {  //int res = sendto(fd, buf, len, 0, (struct sockaddr *) & remote_addr, sizeof(remote_addr));  int res = send(fd, buf, (unsigned int) len , 0);  if (res != len ) {    WARNING_OUT << "\n res " << res << " len= " << len;     return false ;  }  return true;}int  TCPsocket::recv_msg(char * buf, int max_len) {  int len = recv(fd, buf, max_len, 0);  if( len < 0) {    if( len == -1 && errno == EWOULDBLOCK){      //cout << "-" << flush;    }  }  return len;}bool TCPsocket::close() {  if ( ::close(fd) < 0 )    return false;  return true;}/******************************************************************************/#if 1void which_error() {  switch (errno) {  case EBADF:     std::cerr << "  sockfd is not a valid descriptor."; break;   case EINVAL:     std::cerr << " The socket is already bound to  an  address.   This\n"              << "may change in the future: see linux/unix/sock.c for\n"              << "details.\n";     break;   case EACCES: std::cerr << " The address is protected, and the user is not\n"                         << " the super-user.\n"; break;   case ENOTSOCK: std::cerr << "Argument is a descriptor for a file, not a\n"                           << "socket.\n"                           << "\n"                           << "The following errors are specific to UNIX\n"                           << "domain (AF_UNIX)\n"                           << "sockets:\n"; break;#if 0   case EINVAL: std::cerr << " The addrlen is wrong, or the socket was not\n"                         << " in the AF_UNIX family.\n"; break; #endif  case EROFS: std::cerr << "  The socket inode would reside on a  read-only\n"                        << "  file system.\n"; break;   case EFAULT: std::cerr << " my_addr   points   outside  the  user's\n"                         << "accessible address space.\n"; break;   case ENAMETOOLONG: std::cerr << " my_addr is too long.\n"; break;   case ENOENT: std::cerr << " The file does not exist.\n"; break;   case ENOMEM: std::cerr << " Insufficient kernel memory was available.\n";    break;   case ENOTDIR: std::cerr << "A component of the path prefix is not a\n"                          << "directory.\n"; break; #if 0  case EACCES: std::cerr << " Search  permission  is denied on a component\n"                         << " of the path prefix.\n"; break; #endif  case ELOOP:     std::cerr << "  Too many symbolic links were encountered in resolving\n"              << "  my_addr.\n";  default:    std::cerr << " UNKOWN ERROR\n";  }}#endif bool TCPutils::bind_socket(int fd, sockaddr_in & addr, int port) {  memset((char *) &addr, 0, sizeof(addr)) ;  addr.sin_family           = AF_INET ;  addr.sin_addr.s_addr      = htonl(INADDR_ANY) ;  addr.sin_port             = htons(port) ;     int res= bind(fd, (struct sockaddr *) & addr, sizeof(addr));  if ( res < 0 ) {    ERROR_OUT << "\nbind failure";    which_error();    return false ;  /* Can't bind local address */  }  return true;}bool TCPutils::get_host(const char * host, int port, sockaddr_in & addr) {  struct hostent * host_ent ;  struct in_addr * addr_ptr ;   if((host_ent = (struct hostent *)gethostbyname(host)) == NULL) {    /* Check if a numeric address */    if((int)inet_addr(host) == -1) {      ERROR_OUT << "\ngethostbyname failure";      return false;    }  }  else {    addr_ptr = (struct in_addr *) *host_ent->h_addr_list ;    host = inet_ntoa(*addr_ptr) ;  }  memset((char *) &addr, 0, sizeof(addr)) ;  addr.sin_family		= AF_INET ;  addr.sin_addr.s_addr	= inet_addr(host) ;  addr.sin_port		= htons(port) ;  return true;}bool TCPutils::init_client(const char * host, int host_port, TCPsocket & tcpsocket) {  tcpsocket.fd = socket(PF_INET, SOCK_STREAM, 0);    if( tcpsocket.fd < 0) {    ERROR_OUT << "\nsocket failure";    return false ;       /* Can't open socket. */  }#if 0  int i=1;  //don't use timeout for reuse  setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i));#endif  if ( ! get_host(host,host_port,tcpsocket.remote_addr) )    return false;  int res= connect(tcpsocket.fd, (struct sockaddr *) & tcpsocket.remote_addr, sizeof(tcpsocket.remote_addr));  if (res < 0) {    ERROR_OUT << "\nconnect failure";    return false;  }  return true;}bool TCPutils::set_fd_nonblock(int fd) {/* doc:O_NONBLOCK       The bit that enables nonblocking mode for the file. If this bit is set, read requests on the file can return      immediately with a failure status if there is no input immediately available, instead of blocking. Likewise, write      requests can also return immediately with a failure status if the output can't be written immediately. O_NDELAY       This is a synonym for O_NONBLOCK, provided for compatibility with BSD. FASYNCif you set the FASYNC status flag on a file descriptor (see section File Status Flags), a SIGIO signal is sent whenever inputor output becomes possible on that file descriptor. The process or process group to receive the signal can be selectedby using the F_SETOWN command to the fcntl function. If the file descriptor is a socket, this also selects the recipient ofSIGURG signals that are delivered when out-of-band data arrives on that socket; see section Out-of-Band Data. */  if ( fcntl( fd , F_SETOWN, getpid()) < 0) {    ERROR_OUT << "\nset_fd_nonblock  failure";    return false;  }  int val = fcntl(fd, F_GETFL, 0) ;#if 1   val |= O_NDELAY ;#else  val |= O_NONBLOCK ;#endif  //val |= FASYNC;  if ( fcntl(fd, F_SETFL, val) < 0) {    ERROR_OUT << "\nset_fd_nonblock  failure";    return false;  }  return true;}bool TCPutils::set_fd_sigio(int fd) {/* doc:O_NONBLOCK       The bit that enables nonblocking mode for the file. If this bit is set, read requests on the file can return      immediately with a failure status if there is no input immediately available, instead of blocking. Likewise, write      requests can also return immediately with a failure status if the output can't be written immediately. O_NDELAY       This is a synonym for O_NONBLOCK, provided for compatibility with BSD. FASYNCif you set the FASYNC status flag on a file descriptor (see section File Status Flags), a SIGIO signal is sent whenever inputor output becomes possible on that file descriptor. The process or process group to receive the signal can be selectedby using the F_SETOWN command to the fcntl function. If the file descriptor is a socket, this also selects the recipient ofSIGURG signals that are delivered when out-of-band data arrives on that socket; see section Out-of-Band Data. */  if ( fcntl( fd , F_SETOWN, getpid()) == -1) {    ERROR_OUT << "\nset_fd_sigio  failure";    return false;  }  int val = fcntl(fd, F_GETFL, 0) ;#ifndef FASYNC  // I don't know the Solaris equivalent  // should probably throw exception here.#else  val |= FASYNC;#endif  if ( fcntl(fd, F_SETFL, val) < 0 ) {    ERROR_OUT << "\nset_fd_sigio failure";    return false;  }  return true;}/******************************************************************************/bool TCPserver::init(int port) {  fd = socket(PF_INET, SOCK_STREAM, 0);    if( fd < 0) {    ERROR_OUT << "\nsocket failure";    return false ;       /* Can't open socket. */  }#if 1  int i=1;  //don't use timeout for reuse  setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i));#endif  struct sockaddr_in addr;  if ( ! TCPutils::bind_socket(fd, addr, port) )    return false;  return true;}bool TCPserver::listen() {  int res= ::listen(fd,1); //just accept one connection  if (res) {    ERROR_OUT << "\nlisten failure";    return false;  }  return true;}bool TCPserver::accept(TCPsocket & tcpsocket) {#ifndef HAVE_SOCKLEN_T    size_t len;#else    socklen_t len;#endif  len = sizeof( tcpsocket.remote_addr );  tcpsocket.fd = ::accept(fd, (struct sockaddr *) & tcpsocket.remote_addr, & len);  if ( tcpsocket.fd < 0)    return false;  return true;}bool TCPserver::close() {  if ( ::close(fd) < 0 )    return false;  return true;}/******************************************************************************//*****************************************************************************//*****************************************************************************//*****************************************************************************//*****************************************************************************//***************  T  E  S  T**************************************************/#if 0int recv_data_with_blocking(TCPsocket & sock) {  const int MAXMESG= 10000;  char buf[MAXMESG];  while(1) {    int res= sock.recv_msg(buf,MAXMESG);    cout << "\nrecv_msg       = " << res;    if (res <= 0) {      cout << "\nclosing connection" << flush;      sock.close();      break;    }    else      cout << "\n[" << buf << "]" << flush;  }}int recv_data(TCPsocket & sock) {  const int MAXMESG= 10000;  char buf[MAXMESG];  fd_set rfds;  struct timeval tv;  int retval;  while (1) {    FD_ZERO(&rfds);    //FD_SET(server.fd, &rfds);    FD_SET(sock.fd, &rfds);    int max_fd_plus_1=  sock.fd;    //if (server.fd > max_fd_plus_1) max_fd_plus_1= server.fd;    max_fd_plus_1++;	    /* Wait up to five seconds. */    tv.tv_sec = 5; tv.tv_usec = 0;    retval = select(max_fd_plus_1, &rfds, NULL, NULL, &tv);    /* Don't rely on the value of tv now! */	    //if ( FD_ISSET(server.fd, &rfds) )     //  cout << "\nSERVER recv_msg";    if ( FD_ISSET(sock.fd, &rfds) ) {      int res= sock.recv_msg(buf,MAXMESG);      cout << "\nrecv_msg       = " << res;      if (res <= 0) {	cout << "\nclosing connection" << flush;	sock.close();	break;      }      else	cout << "\n[" << buf << "]" << flush;    }  }}int main(int argc, char ** argv) {  const int MAXMESG= 10000;  char buf[MAXMESG];    if (argc>1) { //client    TCPsocket sock;    bool res= TCPutils::init_client("localhost",20000, sock);    if (res) {      //for (int i=0; i<1000; i++)      //  cout << "\nsend_msg       = " << sock.send_msg("(init BS2k (version 5.25))",20);      cout << "\nsend_msg       = " << sock.send_msg("AAAAAAAAAAAAAAAAAAAAAAAAAAA",20);    }    char ch;    cin >> ch;    sock.close();    return 0;  }  TCPserver server;  cout << "\nserver.init= " << server.init(20000) << flush;  cout << "\nlisten     = " << server.listen() << flush;  TCPsocket sub_sock;#if 0  //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>  while ( server.accept(sub_sock) ) {    cout << "\n serverfd= " << server.fd << " data from " << sub_sock.fd << flush;     ////int len = recv(sub_sock.fd, buf, MAXMESG, 0);#if 0    int len= sub_sock.recv_msg(buf,MAXMESG);    cout << "\n got " << len << "bytes= [" << buf << "]" << flush;#else    //recv_data(sub_sock);    recv_data_with_blocking(sub_sock);#endif      }    cout << "\nend" << endl;  return 0;  //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<#endif  #if 1  fd_set rfds;  struct timeval tv;  int retval;  while (1) {    FD_ZERO(&rfds);    //FD_SET(0, &rfds); //Standardeingabe    FD_SET(server.fd, &rfds);    int max_fd_plus_1=  server.fd+1;        /* Wait up to five seconds. */    tv.tv_sec = 5; tv.tv_usec = 0;    retval = select(max_fd_plus_1, &rfds, NULL, NULL, &tv);    /* Don't rely on the value of tv now! */        if (retval <= 0) {      cout << "\nretval= " << retval << flush;      continue;    }        if ( FD_ISSET( server.fd,&rfds) ) {      bool res= server.accept(sub_sock);      if ( ! res) {	cout << "\nnothing to accept" << flush;	continue;      }      cout << "\n data from " << sub_sock.fd << flush;       //continue; // <=================== DEBUG      //TCPutils::set_fd_nonblock(sub_sock.fd); //should be indifferent here      recv_data(sub_sock);          }  }#endif}#endif 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -