socket.cpp

来自「FreeFem++可以生成高质量的有限元网格。可以用于流体力学」· C++ 代码 · 共 558 行 · 第 1/2 页

CPP
558
字号
// -*- Mode : c++ -*-//// SUMMARY  :      // USAGE    :        // ORG      : // AUTHOR   : Antoine Le Hyaric -// E-MAIL   : lehyaric@ann.jussieu.fr///*  This file is part of Freefem++  Freefem++ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.  Freefem++  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 Lesser General Public License for more details.  You should have received a copy of the GNU Lesser General Public License along with Freefem++; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */// Communication between client and server through sockets// -------------------------------------------------------// Antoine Le Hyaric - LJLL Paris 6 - lehyaric@ann.jussieu.fr - 21/10/04// $Id: socket.cpp,v 1.12 2006-09-29 20:30:15 hecht Exp $#include <iostream>#include <cassert>#include "socket.hpp"using namespace std;// Default constructorSocket::Socket(){  socketfd=0;  remotehostname="";  eof=true;}// Create a socket which opens the given TCP port to wait for calls.Socket::Socket(const Port port){  Init();  Open(port);  eof=false;}// Create a socket that calls a given machineSocket::Socket(const string hostname,const Port port){  Init();  Connect(hostname,port);  eof=false;}// Create a socket object from an already-open system socket// descriptor and a host name.Socket::Socket(const descriptor d,const string hostname){  socketfd=d;  remotehostname=hostname;  eof=false;}void Socket::IgnoreSigpipe(){#ifndef __MINGW32__  struct sigaction act;  if(sigaction(SIGPIPE,(struct sigaction *)NULL,&act) < 0)    throw string("Socket::ignore_sigpipe: sigaction error 1");  if(act.sa_handler == SIG_DFL){    act.sa_handler = SIG_IGN;    if(sigaction(SIGPIPE,&act,(struct sigaction *)NULL) < 0)      throw string("Socket::ignore_sigpipe: sigaction error 2");  }#endif}void Socket::Init(){#ifdef __MINGW32__  // (Code fragment found in WSAStartup() manual page in Microsoft  // Visual C++).  WORD wVersionRequested;  WSADATA wsaData;  int err;   wVersionRequested = MAKEWORD(2,0);   err = WSAStartup( wVersionRequested, &wsaData );  // Cannot call WSAGetLastError() since DLL is not initialized yet.  if(err != 0) throw string("Socket::Init: ")+ErrorString();   // Confirm that the WinSock DLL supports 2.0.  Note that if the DLL  // supports versions greater than 2.0 in addition to 2.0, it will  // still return 2.0 in wVersion since that is the version we  // requested.   if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 0){    WSACleanup();    throw string("Socket::Init: Incompatible versions");  }   // The WinSock DLL is acceptable. Proceed.#endif // __MINGW32__}void Socket::CleanUp(){#ifdef __MINGW32__  // Microsoft manual pages say WSAGetLastError() can be used.  if(WSACleanup()==SOCKET_ERROR)    throw string("Socket::CleanUp: ")+ErrorString();#endif}void Socket::Open(const Port port){  IgnoreSigpipe();  socketfd=socket(AF_INET,SOCK_STREAM,0);  if(socketfd<0) throw string("Socket::open::socket: ")+ErrorString();  SockAddrIn server;  server.sin_family = AF_INET;  server.sin_addr.s_addr = INADDR_ANY;  server.sin_port = htons((short)port);  if(bind(socketfd,(SockAddr *)&server,sizeof(server)) < 0     || listen(socketfd,SOMAXCONN) < 0)    throw string("Socket::open::bind/listen: ")+ErrorString();}Socket Socket::Listen(){  SockAddrIn net_client;  descriptor d;#ifdef __MINGW32__  int len=sizeof(SockAddr);  d=accept(socketfd,(SockAddr*)&net_client,&len);#else  socklen_t len=sizeof(SockAddr);  while((d=accept(socketfd,(SockAddr*)&net_client,&len))<0	&& errno == EINTR);#endif  if(d < 0) throw string("Socket::Listen: ")+ErrorString();  string hostname;  HostEnt *hostptr =    gethostbyaddr((char*)&(net_client.sin_addr.s_addr),4,AF_INET);  if(hostptr == NULL) hostname = "unknown";  else hostname = hostptr->h_name;  return Socket(d,hostname);}string Socket::getremotehostname() const{return remotehostname;}void Socket::Connect(const string hostname,const Port port){  IgnoreSigpipe();  HostEnt *hp;  if(!(hp = gethostbyname(hostname.c_str()))     || (socketfd = socket(AF_INET,SOCK_STREAM,0)) < 0)    throw string("Socket::connect: ")+ErrorString();  SockAddrIn server;  memcpy((char*)&server.sin_addr,hp->h_addr_list[0],hp->h_length);  server.sin_port = htons((short)port);  server.sin_family= AF_INET;  int retval;#ifdef __MINGW32__  retval=connect(socketfd,(SockAddr*)&server,sizeof(server));#else  while((retval = connect(socketfd,(SockAddr *)&server,sizeof(server))) < 0	&& errno == EINTR);#endif  if(retval < 0) throw string("Socket::Connect: ")+ErrorString();}void Socket::Close(){#ifdef __MINGW32__#define SOCKET_CLOSE(x) closesocket(x)#else#define SOCKET_CLOSE(x) close(x)#endif  if(SOCKET_CLOSE(socketfd)<0)    throw string("Socket::Close: ")+ErrorString();  CleanUp();}int Socket::Read(char *buf,int size){#ifdef SOCKET_DEBUG  printf("Socket::Read: expecting %d bytes\n",size);  // coherency checks (these are heuristic, they are only useful for  // SOCKET_DEBUG)  assert(size>0 && size<100000);#endif  int retval;#ifdef __MINGW32__  // This must be a blocking call! Otherwise this thread takes 100% of  // processing power, leaving nothing to the server thread (or we  // would have to increase the priority of the server, which is not  // right if we want to have a responsive client).  while((retval=recv(socketfd,buf,size,0))<0	&& WSAGetLastError()==WSAEWOULDBLOCK) Yield();#else  while((retval = read(socketfd,buf,size))<0 && errno==EINTR);#endif  // Checks that everything went fine during the read  if(retval<0) throw string("Socket::Read: ")+ErrorString();  eof=retval==0;  // Debug output#ifdef SOCKET_DEBUG  printf("Socket::Read: \"");  int i;  for(i=0;i<retval;i++){#ifdef SOCKET_STRINGS    printf("%c",buf[i]);#else    printf("%u ",buf[i]);#endif  }  printf("\" length=%d\n",retval);#endif  return retval;}int Socket::Write(const char *buf,int size){#ifdef SOCKET_DEBUG  printf("Socket::Write: \"");  int i;  for(i=0;i<size;i++){#ifdef SOCKET_STRINGS    printf("%c",buf[i]);#else    printf("%u ",buf[i]);#endif  }  printf("\" length=%d\n",size);#endif  int retval;#ifdef __MINGW32__  retval=send(socketfd,buf,size,0);  if(retval==SOCKET_ERROR || retval!=size)    throw string("Socket::Write: ")+ErrorString();#else  while((retval=send(socketfd,buf,size,0))<0 && errno==EINTR);  if(retval<0) throw string("Socket::Write: ")+ErrorString();#endif  return retval;}// Uses unbuffered writes (for debugging)//#define UNBUFFERED_WRITESvoid Socket::bufferedwrite(const char *buf,int size){#ifdef UNBUFFERED_WRITES  Write(buf,size);#else  // Just stores it up until someone calls writeflush()  writebuffer.append(buf,size);  // Avoid sending too much data at any one time, to avoid any  // indigestion in the socket.  if(writebuffer.size()>200) writeflush();#endif

⌨️ 快捷键说明

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