// Пример TCP – сервера подсчета указанного символа в полученном тексте #define _WINSOCK_DEPRECATED_NO_WARNINGS #define _CRT_SECURE_NO_WARNINGS #include #include #include // Wincosk2.h должен быть // подключен раньше windows.h! #include // подключение библиотеки #pragma comment(lib,"Ws2_32.lib") #define PORT 666 // макрос для печати количества активных // пользователей #define PRINTNUSERS if(nclients)\ printf("%d user on-line\n",nclients);\ else printf("No User on line\n"); // прототип функции, обслуживающий // подключившихся пользователей DWORD WINAPI dostuff(LPVOID client_socket); // глобальная переменная – количество // активных пользователей int nclients = 0; // функция по варианту int myfunc(char* a, char c) { int total = 0; FILE* hdl; char message[80] = { 0 }; if (hdl = fopen(a, "rt")) { // цикл чтения до конца файла while (!feof(hdl)) { // чтение одного символа из файла if ((char)fgetc(hdl) == c) total++; } // сообщение в консоль printf("(Server): file:%s, symbols = %d\n", a, total); // закрытие файла fclose(hdl); } else { // сообщение в канал sprintf(message, "(Server)Can't open %s!", a); strcpy(a, message); total = -1; } return total; } int main(int argc, char* argv[]) { char buff[1024]; // Буфер для различных нужд printf("TCP SERVER DEMO\n"); // Шаг 1 - Инициализация Библиотеки Сокетов // Т.к. возвращенная функцией информация // не используется ей передается указатель на // рабочий буфер, преобразуемый // к указателю на структуру WSADATA. // Такой прием позволяет сэкономить одну // переменную, однако, буфер должен быть не менее // полкилобайта размером (структура WSADATA // занимает 400 байт) if (WSAStartup(0x0202, (WSADATA*)&buff[0])) { // Ошибка! printf("Error WSAStartup %d\n", WSAGetLastError()); return -1; } // Шаг 2 - создание сокета SOCKET mysocket; // AF_INET - система адресации // SOCK_STREAM - потоковый сокет (TCP) // 0 - по умолчанию выбирается TCP протокол if ((mysocket = socket(AF_INET, SOCK_STREAM, 0)) < 0) { // Ошибка! printf("Error socket %d\n", WSAGetLastError()); WSACleanup(); // Деиницилизация библиотеки Winsock return -1; } // Шаг 3 связывание сокета с локальным адресом sockaddr_in local_addr; local_addr.sin_family = AF_INET; // задание системы адресации local_addr.sin_port = htons(PORT); // задние порта local_addr.sin_addr.s_addr = INADDR_ANY; // сервер принимает подключения // на все IP-адреса // вызываем bind для связывания if (bind(mysocket, (sockaddr*)&local_addr, sizeof(local_addr))) { // обработка ошибка printf("Error bind %d\n", WSAGetLastError()); closesocket(mysocket); // закрываем сокет! WSACleanup(); return -1; } // Шаг 4 ожидание подключений // размер очереди – 0x100 if (listen(mysocket, 0x100)) { // Ошибка printf("Error listen %d\n", WSAGetLastError()); closesocket(mysocket); WSACleanup(); return -1; } printf("Listen...\n"); // Шаг 5 извлекаем сообщение из очереди SOCKET client_socket; // сокет клиента sockaddr_in client_addr; // адрес клиента // (заполняется системой) // функции accept необходимо передать размер структуры int client_addr_size = sizeof(client_addr); // цикл извлечения запросов на подключение из очереди while ((client_socket = accept(mysocket, (sockaddr*) &client_addr, &client_addr_size))) { nclients++; // увеличиваем счетчик // подключившихся клиентов // вывод сведений о клиенте HOSTENT* hst; hst = gethostbyaddr((char*)&client_addr.sin_addr.s_addr, 4, AF_INET); printf("+%s [%s] new connect!\n", (hst) ? hst->h_name : "", inet_ntoa(client_addr.sin_addr)); PRINTNUSERS // Вызов нового потока для обслужвания клиента DWORD thID; CreateThread(NULL, NULL, dostuff, &client_socket, NULL, &thID); } return 0; } // Эта функция создается в отдельном потоке и // обсуживает очередного подключившегося клиента // независимо от остальных DWORD WINAPI dostuff(LPVOID client_socket) { SOCKET my_sock; my_sock = ((SOCKET*)client_socket)[0]; char* buff = (char*)calloc(1024, sizeof(char)); #define str1 "Enter filename up to 1024 bytes\r\n" #define str2 "Enter symbol for counting\r\n" // отправляем клиенту сообщение send(my_sock, str1, sizeof(str1), 0); int bytes_recv, len, lenstr; // размер принятого сообщения char c; // переменные для myfunc char* a = (char*)calloc(1024, sizeof(char)); char bytes[3] = { 0 }; if ((len = recv(my_sock, bytes, 2, 0)) > 0 && len != SOCKET_ERROR) // принятие длины сообщения от клиента printf("Wait %s bytes...\n", bytes); len = atoi(bytes); lenstr = len; if (((bytes_recv = recv(my_sock, buff, len, 0)) == len) && bytes_recv != SOCKET_ERROR) // принятие сообщения от клиента { printf("Get %d bytes:%s\n", bytes_recv, buff); strncpy(a, buff, bytes_recv); // копирование текста для освобождения буфера //a[len] = '\n'; ZeroMemory(buff, sizeof(buff)); send(my_sock, str2, sizeof(str2), 0); // отправляем клиенту сообщение } // обработка второго параметра ZeroMemory(bytes, sizeof(bytes)); bytes_recv = 0; if ((len = recv(my_sock, bytes, 2, 0)) > 0 && len != SOCKET_ERROR) // принятие длины сообщения от клиента printf("Wait %s byte(s)...\n", bytes); len = atoi(bytes); lenstr = len; if ((bytes_recv = recv(my_sock, buff, len, 0) > 0) && bytes_recv != SOCKET_ERROR) // принятие сообщения от клиента { printf("Get char:%s\n", buff); //символ для подсчета c = buff[0]; // len = myfunc(a, c); // вызов пользовательской функции ZeroMemory(buff, sizeof(buff)); _itoa(len, bytes, 10); // преобразование результата выполнения в строку if (len >= 0) { strcpy(buff, "Answer:"); strcat(buff, bytes); } else strcat(buff, a); buff[strlen(buff)] = '\n';// '\n'; // добавление к сообщению символа конца строки printf("Server:%s\n", buff); buff[strlen(buff) + 1] = '\r'; send(my_sock, buff, strlen(buff), 0); // отправляем клиенту результат } nclients--; // уменьшаем счетчик активных клиентов printf("-disconnect\n"); PRINTNUSERS // закрываем сокет closesocket(my_sock); return 0; }