c sockets class for windows

Upload: thediaugustus829

Post on 14-Apr-2018

220 views

Category:

Documents


0 download

TRANSCRIPT

  • 7/27/2019 c Sockets Class for Windows

    1/8

    Ren Nyffenegger's collection of things on the webRen Nyffenegger on Oracle - Most wanted - Feedback

    C++ Socket Class for Windows

    Here, I present the source code for a socket class that faciliatesusing Sockets in Windows Programming. I also want to saythanks Fabien Le Lez, www.infflux.comand Tamas Kaskotowho have improved this source.

    This socket class is being used for BROADCAST chat client.

    These are actually four classes: Socket (the base class) fromwhich SocketServer and SocketClient are derived. Also, thereis SocketSelect which can be used to do a Select call on morethan one Socket. The constructors of Socket are protected; thisshould be a taken as a hint not to use Socket, but eitherSocketServer or SocketClient.

    When you compile this files, make sure you link them againstWs2_32.lib.

    Jump to the header file, the implementation file, the testprogramm and the Echo Server. Here's also a Proxy and a WebServer.

    You can also download the files.

    A small description of the socket class: Every program that usesWindows Sockets needs to call WSAStartup. This call is wrappedinto Socket::Start, which in turn is called by the Socket'sconstructor. I pass 2.0 as version here as I expect that version to

    be installed.The Socket's constructor also calls socket() (note the small s)which actually creates the socket. It passes the SOCK_STREAMparameter, indicating TCP. If UDP were wished, you'd have topass SOCK_DGRAM.

    SocketClient: SocketClient is inherited from Socket.The constructor of SocketClient takes a host as parameter, whichis the name of the server that this client wishes to communicateto. This name is resolved into an IP Address by gethostbyname().

    SocketServer: SocketServer is inherited from Socket.The constructor of the SocketServer class listens on the portindicated in its parameter. This is made by calling bind().As SOCK_STREAM type sockets have the ability to queueincoming connection requests, we need to know the maximumnumber of connections to be queued which can be stated by theconnections parameter (and which is passed to listen()).SocketServer::Accept(): simply waits for an incomingconnection request (or removes one from the queue) by callingaccept (note the small a).

    The header filesocket.h

    /*Socket.h

    Copyright (C) 2002-2004 Ren Nyffenegger

    This source code is provided 'as-is', without any express or impliedwarranty. In no event will the author be held liable for any damagesarising from the use of this software.

    Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute itfreely, subject to the following restrictions:

    1. The origin of this source code must not be misrepresented; you must notclaim that you wrote the original source code. If you use this source codein a product, an acknowledgment in the product documentation would beappreciated but is not required.

    2. Altered source versions must be plainly marked as such, and must not bemisrepresented as being the original source code.

    3. This notice may not be removed or altered from any source distribution.

    Ren Nyffenegger [email protected]*/

    #ifndef SOCKET_H#define SOCKET_H

    #include

    #include

    enum TypeSocket {BlockingSocket, NonBlockingSocket};

    class Socket {public:

    virtual ~Socket();

    Page 1 of 8C++ Socket Class for Windows

    10/20/2011http://www.adp-gmbh.ch/win/misc/sockets.html

  • 7/27/2019 c Sockets Class for Windows

    2/8

    Socket(const Socket&);Socket& operator=(Socket&);

    std::string ReceiveLine();std::string ReceiveBytes();

    void Close();

    // The parameter of SendLine is not a const reference// because SendLine modifes the std::string passed.void SendLine (std::string);

    // The parameter of SendBytes is a const reference// because SendBytes does not modify the std::string passed

    // (in contrast to SendLine).void SendBytes(const std::string&);

    protected:friend class SocketServer;friend class SocketSelect;

    Socket(SOCKET s);Socket();

    SOCKET s_;

    int* refCounter_;

    private:static void Start();static void End();static int nofSockets_;

    };

    class SocketClient : public Socket {public:

    SocketClient(const std::string& host, int port);};

    class SocketServer : public Socket {public:SocketServer(int port, int connections, TypeSocket type=BlockingSocket);

    Socket* Accept();};

    // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winsock/wsapiref_2tiq.aspclass SocketSelect {public:SocketSelect(Socket const * const s1, Socket const * const s2=NULL, TypeSocket type=BlockingSocket);

    bool Readable(Socket const * const s);

    private:fd_set fds_;

    };

    #endif

    The implementation filesocket.cpp

    /*Socket.cpp

    Copyright (C) 2002-2004 Ren Nyffenegger

    This source code is provided 'as-is', without any express or impliedwarranty. In no event will the author be held liable for any damagesarising from the use of this software.

    Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute itfreely, subject to the following restrictions:

    1. The origin of this source code must not be misrepresented; you must notclaim that you wrote the original source code. If you use this source codein a product, an acknowledgment in the product documentation would beappreciated but is not required.

    2. Altered source versions must be plainly marked as such, and must not bemisrepresented as being the original source code.

    3. This notice may not be removed or altered from any source distribution.

    Ren Nyffenegger [email protected]*/

    #include "Socket.h"#include

    using namespace std;

    int Socket::nofSockets_= 0;

    void Socket::Start() {if (!nofSockets_) {

    Page 2 of 8C++ Socket Class for Windows

    10/20/2011http://www.adp-gmbh.ch/win/misc/sockets.html

  • 7/27/2019 c Sockets Class for Windows

    3/8

    WSADATA info;if (WSAStartup(MAKEWORD(2,0), &info)) {throw "Could not start WSA";

    }}++nofSockets_;

    }

    void Socket::End() {WSACleanup();

    }

    Socket::Socket() : s_(0) {Start();

    // UDP: use SOCK_DGRAM instead of SOCK_STREAMs_ = socket(AF_INET,SOCK_STREAM,0);

    if (s_ == INVALID_SOCKET) {throw "INVALID_SOCKET";

    }

    refCounter_ = new int(1);}

    Socket::Socket(SOCKET s) : s_(s) {Start();refCounter_ = new int(1);

    };

    Socket::~Socket() {if (! --(*refCounter_)) {Close();delete refCounter_;

    }

    --nofSockets_;if (!nofSockets_) End();

    }

    Socket::Socket(const Socket& o) {refCounter_=o.refCounter_;(*refCounter_)++;s_ =o.s_;

    nofSockets_++;}

    Socket& Socket::operator=(Socket& o) {(*o.refCounter_)++;

    refCounter_=o.refCounter_;s_ =o.s_;

    nofSockets_++;

    return *this;}

    void Socket::Close() {closesocket(s_);

    }

    std::string Socket::ReceiveBytes() {std::string ret;char buf[1024];

    while (1) {u_long arg = 0;if (ioctlsocket(s_, FIONREAD, &arg) != 0)break;

    if (arg == 0)break;

    if (arg > 1024) arg = 1024;

    int rv = recv (s_, buf, arg, 0);if (rv

  • 7/27/2019 c Sockets Class for Windows

    4/8

    // if (errno == EAGAIN) {// return ret;// } else {// // not connected anymore// return "";// }

    }

    ret += r;if (r == '\n') return ret;

    }}

    void Socket::SendLine(std::string s) {

    s += '\n';send(s_,s.c_str(),s.length(),0);}

    void Socket::SendBytes(const std::string& s) {send(s_,s.c_str(),s.length(),0);

    }

    SocketServer::SocketServer(int port, int connections, TypeSocket type) {sockaddr_in sa;

    memset(&sa, 0, sizeof(sa));

    sa.sin_family = PF_INET;sa.sin_port = htons(port);s_ = socket(AF_INET, SOCK_STREAM, 0);if (s_ == INVALID_SOCKET) {throw "INVALID_SOCKET";

    }

    if(type==NonBlockingSocket) {u_long arg = 1;ioctlsocket(s_, FIONBIO, &arg);

    }

    /* bind the socket to the internet address */if (bind(s_, (sockaddr *)&sa, sizeof(sockaddr_in)) == SOCKET_ERROR) {closesocket(s_);throw "INVALID_SOCKET";

    }

    listen(s_, connections);}

    Socket* SocketServer::Accept() {SOCKET new_sock = accept(s_, 0, 0);if (new_sock == INVALID_SOCKET) {int rc = WSAGetLastError();if(rc==WSAEWOULDBLOCK) {return 0; // non-blocking call, no request pending

    }else {throw "Invalid Socket";

    }}

    Socket* r = new Socket(new_sock);return r;

    }

    SocketClient::SocketClient(const std::string& host, int port) : Socket() {std::string error;

    hostent *he;if ((he = gethostbyname(host.c_str())) == 0) {error = strerror(errno);throw error;

    }

    sockaddr_in addr;addr.sin_family = AF_INET;addr.sin_port = htons(port);addr.sin_addr = *((in_addr *)he->h_addr);memset(&(addr.sin_zero), 0, 8);

    if (::connect(s_, (sockaddr *) &addr, sizeof(sockaddr))) {error = strerror(WSAGetLastError());throw error;

    }}

    SocketSelect::SocketSelect(Socket const * const s1, Socket const * const s2, TypeSocket type) {FD_ZERO(&fds_);FD_SET(const_cast(s1)->s_,&fds_);if(s2) {FD_SET(const_cast(s2)->s_,&fds_);

    }

    TIMEVAL tval;tval.tv_sec = 0;tval.tv_usec = 1;

    TIMEVAL *ptval;if(type==NonBlockingSocket) {ptval = &tval;

    }else {

    Page 4 of 8C++ Socket Class for Windows

    10/20/2011http://www.adp-gmbh.ch/win/misc/sockets.html

  • 7/27/2019 c Sockets Class for Windows

    5/8

    ptval = 0;}

    if (select (0, &fds_, (fd_set*) 0, (fd_set*) 0, ptval) == SOCKET_ERROR)throw "Error in select";

    }

    bool SocketSelect::Readable(Socket const* const s) {if (FD_ISSET(s->s_,&fds_)) return true;return false;

    }

    A simple Client

    The following simple client connects to www.google.ch and getits front-website.

    #include "Socket.h"

    #include

    using namespace std;

    int main() {

    try {SocketClient s("www.google.com", 80);

    s.SendLine("GET / HTTP/1.0");s.SendLine("Host: www.google.com");s.SendLine("");

    while (1) {string l = s.ReceiveLine();if (l.empty()) break;cout

  • 7/27/2019 c Sockets Class for Windows

    6/8

    delete s;

    return 0;}

    intmain(int argc, char* argv[]) {SocketServer in(2000,5);

    while (1) {Socket* s=in.Accept();

    unsigned ret;_beginthreadex(0,0,Answer,(void*) s,0,&ret);

    }

    return 0;}

    A Proxy that uses the Socket class

    You need the Chameleon class to compile this proxy.

    Usage:proxy .

    This proxy will then listen on and whenever itreceives a connection, relays the traffic to the of. This makes it ideal to see what an SMTP Clientexchanges with a SMTP Server, or equally what a NNTP clientexchanges with an NNTP Server.

    Proxy.cpp

    /*Proxy.cpp

    Copyright (C) 2002-2004 Ren Nyffenegger

    This source code is provided 'as-is', without any express or impliedwarranty. In no event will the author be held liable for any damagesarising from the use of this software.

    Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute itfreely, subject to the following restrictions:

    1. The origin of this source code must not be misrepresented; you must notclaim that you wrote the original source code. If you use this source codein a product, an acknowledgment in the product documentation would beappreciated but is not required.

    2. Altered source versions must be plainly marked as such, and must not bemisrepresented as being the original source code.

    3. This notice may not be removed or altered from any source distribution.

    Ren Nyffenegger [email protected]*/

    #include "Socket.h"

    #include #include #include

    int portProxy;std::string addrServer;int portServer;

    unsigned __stdcall RunProxyThread(void* a) {Socket* s = (Socket*) a;SocketClient c(addrServer, portServer);

    while (1) {SocketSelect sel(s, &c);

    bool still_connected = true;

    if (sel.Readable(s)) {std::string bytes = s->ReceiveBytes();c.SendBytes(bytes);std::cout

  • 7/27/2019 c Sockets Class for Windows

    7/8

    std::cout

  • 7/27/2019 c Sockets Class for Windows

    8/8

    return 0;

    }

    int main() {SocketServer in(2000,5);

    while (1) {Socket* s=in.Accept();

    unsigned ret;_beginthreadex(0,0,Connection,(void*) s,0,&ret);

    }

    return 0;}

    Download the files

    You can download the source code and the exefiles as a zip fileconsisting of

    socket.h

    Chameleon.h

    Chameleon.cpp

    EchoServer.cpp

    MsgDistributor.cpp

    Proxy.cpp

    Socket.cpp

    EchoServer.exe

    Proxy.exe

    makefile

    I was able to compile the sources with mingw using the suppliedmakefile.

    Thanks

    Thanks to Eugene Wee and Nathan Vander Wilt who helpedme improve the socket class.

    Page 8 of 8C++ Socket Class for Windows