T
T
tvsjke2015-02-19 11:35:00
C++ / C#
tvsjke, 2015-02-19 11:35:00

How does WinSock::accept work?

Good afternoon, I'm trying to figure out the following program:

#pragma once
#pragma comment(lib, "WS2_32.lib")
#include <ws2tcpip.h>
#include <string>
#include <winsock2.h>
#include <iostream>
#include <conio.h>

class TCPSocket
{
public:
  enum SOCKET_STATE {INACTIVE,LISTENING,CONNECTED};
  TCPSocket();
  virtual ~TCPSocket();
  static void Startup();
  static void Cleanup();
  int Listen(const unsigned short listenPort);
  int Connect(const std::string& connectAddress,const unsigned short connectPort);
  int Accept(TCPSocket* pAcceptSocket);
  int Send(const char* dataBuffer,const int dataLength,const bool fixedLength=false);
  int Receive(char* dataBuffer,const int dataLength,const bool fixedLength=false);
  int Shutdown();
  std::string GetAddress();
  inline TCPSocket::SOCKET_STATE State();
protected:
private:
  static bool wsaStarted; 
  static WSADATA wsaData;
  SOCKET m_socket;
  sockaddr_in m_socketAddress;
  socklen_t m_addressLength;
  TCPSocket::SOCKET_STATE m_socketState;
};

#include "tcp_socket.h"

bool TCPSocket::wsaStarted=false;
WSADATA TCPSocket::wsaData=WSADATA();

TCPSocket::TCPSocket()
{
  if(!TCPSocket::wsaStarted) TCPSocket::Startup();
  this->m_socket=INVALID_SOCKET;
  memset(static_cast<void*>(&this->m_socketAddress),0,sizeof(this->m_socketAddress));
  this->m_addressLength=sizeof(this->m_socketAddress);
  this->m_socketState=TCPSocket::INACTIVE;
}

TCPSocket::~TCPSocket()
{
  if(this->m_socket!=INVALID_SOCKET) this->Shutdown();
}

void TCPSocket::Startup()
{
  if(!TCPSocket::wsaStarted)
  {
    TCPSocket::wsaStarted=true;
    ::WSAStartup(WINSOCK_VERSION,&wsaData); 
  }
}

void TCPSocket::Cleanup()
{
  if(TCPSocket::wsaStarted)
  {
    TCPSocket::wsaStarted=false;
    ::WSACleanup(); 
  }
}

int TCPSocket::Listen(const unsigned short listenPort)
{
  if(this->m_socketState!=TCPSocket::INACTIVE) return -1;
  this->m_socketAddress.sin_family=AF_INET;
  this->m_socketAddress.sin_addr.S_un.S_addr=ADDR_ANY;
  this->m_socketAddress.sin_port=htons(listenPort);
  this->m_socket=::socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
  if(this->m_socket==INVALID_SOCKET) return ::WSAGetLastError();
  if(::bind(this->m_socket,reinterpret_cast<sockaddr*>(&this->m_socketAddress),this->m_addressLength)==SOCKET_ERROR) return ::WSAGetLastError();
  if(::listen(this->m_socket,SOMAXCONN)==SOCKET_ERROR) return ::WSAGetLastError();
  this->m_socketState=TCPSocket::LISTENING;
  return 0;
}

int TCPSocket::Connect(const std::string& connectAddress,const unsigned short connectPort)
{
  if(this->m_socketState!=TCPSocket::INACTIVE) return -1;
  this->m_socketAddress.sin_family=AF_INET;
  this->m_socketAddress.sin_addr.S_un.S_addr=::inet_addr(connectAddress.c_str());
  if(this->m_socketAddress.sin_addr.S_un.S_addr==INADDR_NONE)
  {
    hostent* pHost;
    pHost=::gethostbyname(connectAddress.c_str());
    if(pHost!=nullptr)
      if(pHost->h_name!=nullptr)
        if(pHost->h_addr_list!=nullptr)
          if((*(pHost->h_addr_list))!=nullptr)
            this->m_socketAddress.sin_addr.S_un.S_addr=*reinterpret_cast<int*>(*(pHost->h_addr_list));
  }
  this->m_socketAddress.sin_port=htons(connectPort);
  this->m_socket=::socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
  if(this->m_socket==INVALID_SOCKET) return ::WSAGetLastError();
  if(::connect(this->m_socket,reinterpret_cast<sockaddr*>(&this->m_socketAddress),this->m_addressLength)==SOCKET_ERROR) return ::WSAGetLastError();
  this->m_socketState=TCPSocket::CONNECTED;
  return 0;
}

int TCPSocket::Accept(TCPSocket* pAcceptSocket)
{
  if(pAcceptSocket==nullptr) pAcceptSocket=new TCPSocket();
  if(pAcceptSocket->m_socketState!=TCPSocket::INACTIVE) return -1;
  pAcceptSocket->m_socket=::accept(this->m_socket,reinterpret_cast<sockaddr*>(&pAcceptSocket->m_socketAddress),&pAcceptSocket->m_addressLength);
  if(pAcceptSocket->m_socket==INVALID_SOCKET) return ::WSAGetLastError();
  pAcceptSocket->m_socketState=TCPSocket::CONNECTED;
  return 0;
}

int TCPSocket::Send(const char* dataBuffer,const int dataLength,const bool fixedLength)
{
  int socketLength;
  if(this->m_socketState!=TCPSocket::CONNECTED) return -1;
  if(fixedLength)
  {
    socketLength=::send(this->m_socket,dataBuffer,dataLength,0);
    if((socketLength==SOCKET_ERROR)||(socketLength!=dataLength)) return ::WSAGetLastError();
  }
  else
  {
    int data_index=0;
    int data_length=dataLength;
    while(data_length>0)
    {
      socketLength=::send(this->m_socket,dataBuffer+data_index,data_length,0);
      if(socketLength==SOCKET_ERROR) return ::WSAGetLastError();
      data_index+=socketLength;
      data_length-=socketLength;
    }
  }
  return 0;
}

int TCPSocket::Receive(char* dataBuffer,const int dataLength,const bool fixedLength)
{
  int socketLength;
  if(this->m_socketState!=TCPSocket::CONNECTED) return -1;
  if(fixedLength)
  {
    socketLength=::recv(this->m_socket,dataBuffer,dataLength,0);
    if((socketLength==SOCKET_ERROR)||(socketLength!=dataLength)) return ::WSAGetLastError();
  }
  else
  {
    int data_index=0;
    int data_length=dataLength;
    while(data_length>0)
    {
      socketLength=::recv(this->m_socket,dataBuffer+data_index,data_length,0);
      if(socketLength==SOCKET_ERROR) return ::WSAGetLastError();
      data_index+=socketLength;
      data_length-=socketLength;
    }
  }
  return 0;
}

int TCPSocket::Shutdown()
{
  int errCode=0;
  switch(this->m_socketState)
  {
  case TCPSocket::INACTIVE:
    errCode=-1;
    break;
  case TCPSocket::LISTENING:
    if(::closesocket(this->m_socket)==SOCKET_ERROR) errCode=::WSAGetLastError();
    break;
  case TCPSocket::CONNECTED:
    if((::shutdown(this->m_socket,SD_BOTH)==SOCKET_ERROR)||(::closesocket(this->m_socket)==SOCKET_ERROR)) errCode=::WSAGetLastError();
    break;
  }
  this->m_socket=INVALID_SOCKET;
  return errCode;
}

std::string TCPSocket::GetAddress()
{
  char buf[_MAX_INT_DIG*2];
  sprintf(buf,"%d",::ntohs(this->m_socketAddress.sin_port));
  return std::string(::inet_ntoa(this->m_socketAddress.sin_addr))+":"+std::string(buf);
}

inline TCPSocket::SOCKET_STATE TCPSocket::State()
{
  return this->m_socketState;
}

In theory, we first start the server to listen:
TCPSocket* server = new TCPSocket();
server->Listen(27013);

And then connect to it:
TCPSocket* client = new TCPSocket();
сlient->Connect("127.0.0.1", 27013);

But the role of TCPSocket::Accept is not entirely clear (on MSDN it is written that the function roughly speaking creates a new socket with the current connection) ... Can you briefly, on your fingers, explain the sequence of actions (and the actions themselves)
Don't kick me hard, I'm new to the client - server programming

Answer the question

In order to leave comments, you need to log in

2 answer(s)
L
lil_toady, 2015-02-24
@lil_toady

In short:
TCP is a session protocol, and, accordingly, requests to open a connection must be accepted, which is what accept does. Logically, each connected client is a separate socket, which we will receive through accept.

V
Vladimir Martyanov, 2015-02-19
@vilgeforce

citforum.ru/book/cook/winsock.shtml - an article by Chris Kaspersky on the topic. IMHO everything is suitably chewed.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question