@tvsjke
информация засекречена

Как работает WinSock::accept?

День добрый, пытаюсь разобраться со следующей программой:

#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;
}


По идее, сначала запускаем сервер на прослушивание:

TCPSocket* server = new TCPSocket();
server->Listen(27013);


А потом коннектимся к нему:

TCPSocket* client = new TCPSocket();
сlient->Connect("127.0.0.1", 27013);


Но не совсем понятна роль TCPSocket::Accept (на мсдн написано, что функция грубо говоря создает новый сокет с текущим подключением)... Можете вкратце, на пальцах, объяснить последовательность действий(и сами действия)

Сильно не пинайте, я новичок в клиент-серверном программировании
  • Вопрос задан
  • 3699 просмотров
Пригласить эксперта
Ответы на вопрос 2
@lil_Toady
Если кртако:
TCP - сессионный протокол, а соответственно запросы на открытие подключения надо принять, что и делает accept. Логически, каждый подключенный клиент - это отдельный сокет, который через accept мы и получим.
Ответ написан
Комментировать
@vilgeforce
Раздолбай и программист
citforum.ru/book/cook/winsock.shtml - статья Криса Касперски на тему. IMHO все годно разжевано.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы