Клиент-серверное приложение на потоковом сокете TCP. Основы и примеры реализации
Клиент-серверные приложения — это важная часть современного информационного мира. Они позволяют взаимодействовать клиентам и серверам, обмениваться данными и выполнять различные задачи. Одним из самых простейших и надежных протоколов для построения клиент-серверных приложений является TCP.
Протокол TCP (Transmission Control Protocol) обеспечивает надежную передачу данных между сервером и клиентом. В TCP сеть представляется в виде потоков сокетов, по которым передаются данные. Клиент и сервер могут обмениваться сообщениями или даже видео и аудио потоком.
Для создания клиент-серверного приложения с использованием TCP необходимо выполнить несколько шагов. Сначала нужно создать сокет соответствующего типа (клиентский или серверный). Затем клиент должен установить соединение с сервером, используя функцию connect. Сервер, с другой стороны, должен прослушивать соединения и принимать их при поступлении с помощью функции accept.
Для примера рассмотрим создание простейшего клиент-серверного приложения на TCP с использованием языка программирования C++. Создадим сервер, который будет умножать числа, переданные клиентом. Для этого мы создадим класс серверной части приложения, который будет содержать методы для создания сокета, установления соединения и приема данных. Затем мы создадим клиентскую часть, которая будет отправлять числа на сервер и получать результат умножения.
Создание простейшего клиент-серверного приложения
В данной статье мы рассмотрим создание простейшего клиент-серверного приложения с использованием Windows Forms и языка программирования C++. Для реализации сетевого взаимодействия между клиентом и сервером будем использовать сокеты TCP.
Серверная часть
Начнем с создания сервера. Для этого нам понадобятся следующие компоненты:
- Сокет TCP: для установления надежного соединения между клиентами и сервером.
- WSADATA: для инициализации библиотеки сокетов.
Пример простого сервера на C++:
#include <iostream>
#include <winsock2.h>
int main() {
WSADATA wsaData;
int iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if (iResult != 0) {
std::cout << "WSAStartup failed: " << iResult << std::endl;
return 1;
}
SOCKET serverSocket;
serverSocket = socket(AF_INET, SOCK_STREAM, 0);
if (serverSocket == INVALID_SOCKET) {
std::cout << "socket failed: " << WSAGetLastError() << std::endl;
WSACleanup();
return 1;
}
sockaddr_in serverAddress;
serverAddress.sin_family = AF_INET;
serverAddress.sin_addr.s_addr = INADDR_ANY;
serverAddress.sin_port = htons(12345);
iResult = bind(serverSocket, (struct sockaddr*)&serverAddress, sizeof(serverAddress));
if (iResult == SOCKET_ERROR) {
std::cout << "bind failed: " << WSAGetLastError() << std::endl;
closesocket(serverSocket);
WSACleanup();
return 1;
}
if (listen(serverSocket, 1) == SOCKET_ERROR) {
std::cout << "listen failed: " << WSAGetLastError() << std::endl;
closesocket(serverSocket);
WSACleanup();
return 1;
}
std::cout << "Server is running..." << std::endl;
SOCKET clientSocket;
sockaddr_in clientAddress;
int clientAddressSize = sizeof(clientAddress);
while ((clientSocket = accept(serverSocket, (struct sockaddr*)&clientAddress, &clientAddressSize))) {
std::cout << "Client connected" << std::endl;
// В этом месте можно обрабатывать запросы клиента
std::cout << "Client disconnected" << std::endl;
closesocket(clientSocket);
}
closesocket(serverSocket);
WSACleanup();
return 0;
}
Простой сервер создан. В данном примере сервер прослушивает порт 12345 и принимает только одно соединение.
Клиентская часть
Теперь рассмотрим создание клиента. Для работы с сокетами TCP нам понадобится следующий набор компонентов:
- Сокет TCP: для установления соединения с сервером и обмена данными.
- WSADATA: для инициализации библиотеки сокетов.
Пример простого клиента на C++:
#include <iostream>
#include <winsock2.h>
int main() {
WSADATA wsaData;
int iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if (iResult != 0) {
std::cout << "WSAStartup failed: " << iResult << std::endl;
return 1;
}
SOCKET clientSocket;
clientSocket = socket(AF_INET, SOCK_STREAM, 0);
if (clientSocket == INVALID_SOCKET) {
std::cout << "socket failed: " << WSAGetLastError() << std::endl;
WSACleanup();
return 1;
}
sockaddr_in serverAddress;
serverAddress.sin_family = AF_INET;
serverAddress.sin_addr.s_addr = inet_addr("127.0.0.1");
serverAddress.sin_port = htons(12345);
if (connect(clientSocket, (struct sockaddr*)&serverAddress, sizeof(serverAddress)) < 0) {
std::cout << "connect failed: " << WSAGetLastError() << std::endl;
closesocket(clientSocket);
WSACleanup();
return 1;
}
std::cout << "Connected to server" << std::endl;
// В этом месте можно отправлять запросы на сервер и получать ответы
closesocket(clientSocket);
WSACleanup();
return 0;
}
Простой клиент создан. Он устанавливает соединение с сервером, указав адрес и порт, и затем закрывает это соединение.
Данная версия клиент-серверного приложения является простейшей и быстрой, но не даёт больших возможностей в операциях обмена данными. Для более масштабных приложений вместо прямого использования сокетов можно воспользоваться более удобными и надежными методами, такими как WCF или создание собственных классов для работы с сокетами.
Простой и быстрый сервер на C/C++ с клиентом на C: TCP версия
Для создания сервера и клиента на C/C++ с использованием сокетов TCP необходимо включить заголовочные файлы соответствующих библиотек. В Windows это <winsock2.h>
, в Linux – <sys/socket.h>
. Для работы с сокетами в C/C++ также понадобится создание объекта типа WSADATA wsadata;
(в Windows) и инициализация сокетов с помощью функций, таких как WSAStartup
(в Windows) или socket
(в Linux).
После создания и инициализации сокетов сервер должен ожидать на своем сокете клиентские подключения. Для этого необходимо использовать классический цикл ожидания подключений с помощью функций, таких как listen
и accept
. В этот момент сервер создает новый сокет для каждого подключения и обрабатывает запросы клиентов.
Клиент может быть реализован с использованием любого метода для соединения с сервером. В данном случае мы используем TCP сокеты. Клиент должен создать сокет и установить соединение с сервером с помощью функций, таких как connect
или socket
.
Для примера рассмотрим реализацию сервера на языке C/C++:
#include <stdio.h>
#include <stdlib.h>
#include <winsock2.h>
#pragma comment(lib,"ws2_32.lib") //Winsock Library
int main(int argc , char *argv[])
{
WSADATA ws;
SOCKET s , new_socket;
struct sockaddr_in server , client;
int c;
char *message;
printf("
Initialising Winsock...");
if(WSAStartup(MAKEWORD(2,2),&ws) != 0)
{
printf("Failed. Error Code : %d",WSAGetLastError());
return 1;
}
//Create a socket
if((s = socket(AF_INET , SOCK_STREAM , 0 )) == INVALID_SOCKET)
{
printf("Could not create socket : %d" , WSAGetLastError());
}
printf("Socket created.
");
//Prepare the sockaddr_in structure
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons( 8888 );
//Bind
if( bind(s ,(struct sockaddr *)&server , sizeof(server)) == SOCKET_ERROR)
{
printf("Bind failed with error code : %d" , WSAGetLastError());
exit(EXIT_FAILURE);
}
puts("Bind done");
//Listen to incoming connections
listen(s , 3);
//Accept and incoming connection
puts("Waiting for incoming connections...");
c = sizeof(struct sockaddr_in);
new_socket = accept(s , (struct sockaddr *)&client, &c);
if (new_socket == INVALID_SOCKET)
{
printf("accept failed with error code : %d" , WSAGetLastError());
return 1;
}
puts("Connection accepted");
//Reply to the client
message = "Hello Client , I have received your connection. But I have to go now, bye
";
send(new_socket , message , strlen(message) , 0);
closesocket(s);
WSACleanup();
return 0;
}
В данном примере сервер создает сокет, связывает его с определенным адресом и портом, ожидает подключения клиента с помощью функции accept
и отправляет простое текстовое сообщение клиенту с помощью функции send
.
Теперь рассмотрим пример клиента на языке C:
#include <stdio.h>
#include <stdlib.h>
#include <winsock2.h>
#pragma comment(lib,"ws2_32.lib") //Winsock Library
int main(int argc , char *argv[])
{
WSADATA ws;
SOCKET s;
struct sockaddr_in server;
char *message, server_reply[2000];
int recv_size;
printf("
Initialising Winsock...");
if(WSAStartup(MAKEWORD(2,2),&ws) != 0)
{
printf("Failed. Error Code : %d",WSAGetLastError());
return 1;
}
printf("Initialised.
");
//Create a socket
if((s = socket(AF_INET , SOCK_STREAM , 0 )) == INVALID_SOCKET)
{
printf("Could not create socket : %d" , WSAGetLastError());
}
printf("Socket created.
");
server.sin_addr.s_addr = inet_addr("127.0.0.1");
server.sin_family = AF_INET;
server.sin_port = htons( 8888 );
//Connect to remote server
if (connect(s , (struct sockaddr *)&server , sizeof(server)) < 0)
{
printf("connect failed with error code : %d" , WSAGetLastError());
return 1;
}
puts("Connected");
//Receive a reply from the server
if((recv_size = recv(s , server_reply , 2000 , 0)) == SOCKET_ERROR)
{
printf("recv failed with error code : %d" , WSAGetLastError());
}
puts("Reply received
");
//Add a NULL terminating character to make it a proper string before printing
server_reply[recv_size] = '0';
puts(server_reply);
closesocket(s);
WSACleanup();
return 0;
}
В данном примере клиент создает сокет, устанавливает соединение с сервером с помощью функции connect
и получает текстовое сообщение от сервера с помощью функции recv
.
Пример представляет собой простую реализацию клиент-серверного приложения на языках C/C++ с использованием потоковых сокетов TCP. Однако, заметим, что эти примеры не являются готовыми приложениями и используются только для объяснения базовых принципов работы клиент-серверного взаимодействия с использованием сокетов.
Видео:
Кэширование в HTTP | Курс "Компьютерные сети"
Кэширование в HTTP | Курс "Компьютерные сети" by Andrey Sozykin 58,700 views 7 years ago 9 minutes, 47 seconds