Windows Sockets 2. Создание соединения, страница 3

Ожидание запросов клиентов. Функция listen делает сокет сервера доступным для подключения клиентов:

int listen(   //возвращаемое значение 0 в случае успеха или SOCKET_ERROR (WSAGetLastError())

SOCKET s,   // «дескриптор» сокета

int backlog //максимальный размер очереди для подключений клиентов. Можно указать SOMAXCONN, тогда размер будет установлен по умолчанию – наиболее оптимальным образом. Замечание: в WinSock2.0 размер очереди не ограничен.

);

Пример:

{

if ( listen( m_socket, 1 ) == SOCKET_ERROR )

MessageBox( "Error listening","server");

}

2.1.5.  Прием подключения (запроса на соединение) (accept) клиента и обмен данными

Функция accept() блокируется (при синхронном обмене), пока не появляется запрос от клиента.

Когда клиент устанавливает соединение с сервером, система создает (назначает) данному соединению отдельный сокет для ввода/вывода, чтобы иметь возможность продолжать ожидание запроса на подключение от других клиентов на прежнем сокете. Функция accept() возвращает новый «подключенный» сокет, который можно использовать в функциях чтения/записи. При этом исходный сокет находится в режиме прослушивания и ожидает подключения следующего клиента => его дескриптор в функциях чтения/записи не фигурирует. А использовать можно дескриптор исходного сокета только в качестве параметра функции accept() для того, чтобы система могла создать

SOCKET accept(//дескриптор нового сокета с которым установлено соединение для обмена данными или INVALID_SOCKET => WSAGetLastError()

SOCKET s,   //дескриптор «слушающего сокета» - задает программист

struct sockaddr* addr,//указатель на структуру sockaddr_in, в которой будет сформирован «адрес» клиента – заполняет функция accept(). Замечание: если адрес клиента Вам не нужен, то можно указать 0

int* addrlen//перед вызовом задает программист - sizeof(sockaddr_in) заполняет функция accept() Замечание: если адрес клиента Вам не нужен, то можно указать 0

);

Пример:

{

//Ожидание запросов на подключение

SOCKET AcceptSocket =   //сюда получим дескриптор сокета для ввода/вывода

accept( m_socket, NULL, NULL );//в качестве параметра – дескриптор «слушающего» сокета

if(AcceptSocket != SOCKET_ERROR)

{//подключился клиент

MessageBox( "Client Connected", "Server");

//Обмен данными

//NB - по-хорошему для обработки запроса клиента нужно запустить отдельный поток

//Получаем данные от клиента. При этом нужно учесть, что нет гарантии, что все данные будут получены за один раз => нужно проверять возвращаемое функцией recv() значение и повторять прием, пока все данные не будут приняты

char ar[256]={0};//здесь будем "копить" данные

int bytesRecv= SOCKET_ERROR;

while( bytesRecv == SOCKET_ERROR )//повторение приема

{

char tmp[256];//это буфер для очередной порции

bytesRecv = recv( AcceptSocket, tmp, sizeof(tmp), 0 );//можно ReadFile

if ( bytesRecv == 0 || bytesRecv == WSAECONNRESET )

{

MessageBox( "Все данные приняты или клиент разорвал соединение","Sever");

break;

}

strcat(ar,tmp);

}

//Получили все данные

SetDlgItemText(IDC_EDIT1,ar);

//Отправляем эхо

strcat(ar, "Got!");

int bytesSent = send( AcceptSocket, ar, strlen(ar)+1, 0 );//можно WriteFile

//Закрыть сокет ввода/вывода

shutdown(AcceptSocket,2);

closesocket(AcceptSocket);

}

2.1.6.  Завершение соединения

{

shutdown(m_socket,2); //запрещение приема и передачи

closesocket( m_socket);

WSACleanup();

}

2.2.  Клиент

2.2.1.  Инициализация библиотеки WS2_32.DLL

Аналогично серверу

2.2.2.  Создание сокета

Аналогично серверу

2.2.3.  Подключение к серверу

Функция connect блокирует выполнение клиента, пока он не подключится к серверу. Параметры функции аналогичны параметрам bind().

Пример:

{

sockaddr_in clientService;

clientService.sin_family = AF_INET;

clientService.sin_addr.s_addr = inet_addr( "127.0.0.1" );

clientService.sin_port = htons( 27015 );

if ( connect( m_socket, (SOCKADDR*) &clientService, sizeof(clientService) ) == SOCKET_ERROR)

{

MessageBox( "Failed to connect", "Client" );

WSACleanup();

return;

}

}

2.2.4.  Обмен данными

Обмен данными осуществляется функциями send(), recv() (или ReadFile(), WriteFile()).

Пример:

{

int bytesSent;

int bytesRecv = SOCKET_ERROR;

char sendbuf[256] = "Client: Sending data.";

char recvbuf[256] = "";

bytesSent = send( m_socket, sendbuf, strlen(sendbuf)+1, 0 );

while( bytesRecv == SOCKET_ERROR )

{

bytesRecv = recv( m_socket, recvbuf, sizeof(recvbuf), 0 );

if ( bytesRecv == 0 || bytesRecv == WSAECONNRESET )

{

MessageBox( "Получены все данные или сервер разорвал соединение","Client");

break;

}

}

SetDlgItemText( IDC_EDIT1,recvbuf);

}

2.2.5.  Завершение соединения

{

shutdown(m_socket,2); //запрещение приема и передачи

closesocket( m_socket);

WSACleanup();

}