Ожидание запросов клиентов. Функция 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");
}
Функция 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);
}
{
shutdown(m_socket,2); //запрещение приема и передачи
closesocket( m_socket);
WSACleanup();
}
Аналогично серверу
Аналогично серверу
Функция 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;
}
}
Обмен данными осуществляется функциями 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);
}
{
shutdown(m_socket,2); //запрещение приема и передачи
closesocket( m_socket);
WSACleanup();
}
Уважаемый посетитель!
Чтобы распечатать файл, скачайте его (в формате Word).
Ссылка на скачивание - внизу страницы.