Мультиплексирование передачи сообщений ввода-вывода (чат клиент-сервер)
Всем привет,
Я новичок в C (как и в программировании) и изучаю сокеты Windows.
Я хочу написать простой чат между сервером и 2 клиентами (идеально сервер должен отправлять сообщения для всех, клиент только для сервера), и я столкнулся с проблемой.
Что я уже пробовал:
Из части** server * * я не могу получать сообщения от клиента до того, как отправлю сообщение клиенту. Тогда я теряю возможность отправлять сообщения из-за курсивов.
От * * клиента * * часть: клиент не получает сообщение сервера. В чем причина? Я проверил, доступны ли дескрипторы файлов чтения и записи (status = 1).
Кроме того, если я пытаюсь отправить сообщения от клиента, а затем отправить сообщение с сервера, я могу ввести clien console только один раз, а затем получить ошибку 10053 (установленное соединение было прервано программным обеспечением на вашем хост-компьютере, возможно, из-за тайм-аута передачи данных или ошибки протокола), но не могу найти ошибку в серверной части. После этого в серверной части, где я проверяю запись и чтение FD, я начинаю получать свои отладочные сообщения, эти дескрипторы получили статус = 0, и я не понимаю, почему (вероятно, потому что в сокете нет активности? Поскольку это мультиплексирование ввода-вывода, но меня больше интересует моя проблема с сообщением).
Это** сервер * * вывод:
Setup SERVER socket descriptor number: 272 We have 1 user online New client 127.0.0.1:64590 Read FD: 1 Write FD: 1 Server -> Client: Check after 1 and 2 Read FD: 1 Write FD: 1 Client -> Server: Check 1 Check 2 Read FD: 0 Write FD: 0
Это** клиент * * вывод:
Attempt to connect 127.0.0.1:3765 Local address: 127.0.0.1:3765 of server: Connection with 127.0.0.1 Client -> Server: Check 1 Client -> Server: Check 2 Client -> Server: trying to write smth Client -> Server: aaand fail Send error - Error code: 10053
Это код сервера:
#pragma comment(lib, "ws2_32.lib") #define _WINSOCK_DEPRECATED_NO_WARNINGS #define _CRT_SECURE_NO_WARNINGS #include <winsock2.h> #include <stdio.h> #include <stdlib.h> #include <conio.h> //#include "list.h" #define PRINTUSERS if (nclients)\ printf("We have %d user online\n", nclients);\ else printf("No users online\n***************\n"); #define PORT 3765 #define BACKLOG 10 #define MAXDATASIZE 1024 #define MAXUSERSONLINE 64 int main(int argc, char* argv[]) { struct sockaddr_in serverAddr; struct sockaddr_in clientAddr; SOCKET socketDescriptor; fd_set readSocketDescriptor; fd_set writeSocketDescriptor; int newSocketDescriptor; WSADATA wsaData; WORD wsaStart; timeval tv; int retVal; int clientAddrSize = sizeof(clientAddr); char bufferData[MAXDATASIZE] = { 0 }; int nclients = 0; int numBytes = 0; if (argc > 1) { printf("Uses: <chatserver>\n"); return -1; } do { if ((wsaStart = WSAStartup(MAKEWORD(2, 2), &wsaData)) != 0) { printf("WSAStartup error "); break; } if ((socketDescriptor = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) { printf("Socket error "); closesocket(socketDescriptor); break; } serverAddr.sin_family = AF_INET; serverAddr.sin_port = htons(PORT); serverAddr.sin_addr.s_addr = INADDR_ANY; if (bind(socketDescriptor, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) { printf("Bind error "); closesocket(socketDescriptor); break; } if (listen(socketDescriptor, BACKLOG) == SOCKET_ERROR) { printf("Listening error "); closesocket(socketDescriptor); break; } printf("Setup SERVER socket descriptor number: %d\n", socketDescriptor); tv.tv_sec = 5; while (1) { // Do not forget to put after WHILE(1) FD_ZERO(&readSocketDescriptor); FD_ZERO(&writeSocketDescriptor); FD_SET(socketDescriptor, &readSocketDescriptor); FD_SET(socketDescriptor, &writeSocketDescriptor); if ((retVal = select(socketDescriptor + 1, &readSocketDescriptor, &writeSocketDescriptor, NULL, &tv)) == SOCKET_ERROR) { printf("Select error "); break; } if ((FD_ISSET(socketDescriptor, &readSocketDescriptor)) != 0) { if ((newSocketDescriptor = accept(socketDescriptor, (struct sockaddr *)&clientAddr, &clientAddrSize)) == SOCKET_ERROR) { printf("Accept error "); break; } createSocketInformation(newSocketDescriptor); getSocketInformation(newSocketDescriptor); nclients++; PRINTUSERS printf("New client %s:%d \n", inet_ntoa(clientAddr.sin_addr), ntohs(clientAddr.sin_port)); //FD_CLR(socketDescriptor, &readSocketDescriptor); FD_SET(newSocketDescriptor, &readSocketDescriptor); FD_SET(newSocketDescriptor, &writeSocketDescriptor); printf("Read FD: %d\n", FD_ISSET(newSocketDescriptor, &readSocketDescriptor)); printf("Write FD: %d\n", FD_ISSET(newSocketDescriptor, &writeSocketDescriptor)); printf("Server -> Client: "); fgets(&bufferData[0], sizeof(bufferData), stdin); if (FD_ISSET(newSocketDescriptor, &writeSocketDescriptor) != 0) { if (send(newSocketDescriptor, &bufferData[0], MAXDATASIZE, 0) == SOCKET_ERROR) { printf("Send error "); freeSocketInformation(newSocketDescriptor); break; } //FD_CLR(newSocketDescriptor, &writeSocketDescriptor); //FD_SET(newSocketDescriptor, &writeSocketDescriptor); } } printf("Read FD: %d\n", FD_ISSET(newSocketDescriptor, &readSocketDescriptor)); printf("Write FD: %d\n", FD_ISSET(newSocketDescriptor, &writeSocketDescriptor)); if (FD_ISSET(newSocketDescriptor, &readSocketDescriptor) != 0) { if ((numBytes = recv(newSocketDescriptor, &bufferData[0], MAXDATASIZE, 0)) == SOCKET_ERROR) { printf("Recv failed \n"); freeSocketInformation(newSocketDescriptor); break; } bufferData[numBytes] = '\0'; printf("Client -> Server: %s\n", &bufferData[0]); if (numBytes == -1) { printf("One user has disconnected"); nclients--; PRINTUSERS } else { char *testmsg = "Hello, new user, you're welcome\n"; if (send(newSocketDescriptor, testmsg, strlen(testmsg), 0) == SOCKET_ERROR) { printf("Send error "); freeSocketInformation(newSocketDescriptor); break; } FD_CLR(newSocketDescriptor, &readSocketDescriptor); } FD_SET(newSocketDescriptor, &readSocketDescriptor); } /*else { printf("Sorry, time limit is expired, there is no active sockets\n"); freeSocketInformation(newSocketDescriptor); }*/ closesocket(newSocketDescriptor); } closesocket(socketDescriptor); } while (FALSE); printf("- Error code: %d\n", WSAGetLastError()); WSACleanup(); return 0; }
И клиентская часть:
#pragma comment(lib, "ws2_32.lib") #define _WINSOCK_DEPRECATED_NO_WARNINGS #include <winsock2.h> #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <sys/types.h> #define SERVERADDR argv[1] #define PORT 3765 #define MAXDATASIZE 1024 int main(int argc, char *argv[]) { struct sockaddr_in serverAddr = { 0 }; struct sockaddr_in clientAddr = { 0 }; SOCKET socketDescriptor; WSADATA wsaData; fd_set readSet; fd_set writeSet; timeval tv; char bufferData[MAXDATASIZE]; int numBytes; unsigned long int nb = 1; int retVal; if (argc != 2) { printf("Uses: <client> <hostname>\nExample: \"client 127.0.0.1\"\n"); return -1; } do { if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { printf("WSAStartup error "); break; } if (gethostbyname(SERVERADDR) == NULL) { printf("Gethostbyname error "); break; } if ((socketDescriptor = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) { printf("Socket error "); break; } if (ioctlsocket(socketDescriptor, FIONBIO, (unsigned long *)&nb) != 0) { printf("ioctlsocket error "); break; } serverAddr.sin_family = AF_INET; serverAddr.sin_port = htons(PORT); serverAddr.sin_addr.s_addr = inet_addr(SERVERADDR); printf("Attempt to connect %s:%d\n", inet_ntoa(serverAddr.sin_addr), htons(serverAddr.sin_port)); tv.tv_sec = 20; if (connect(socketDescriptor, (sockaddr *)&serverAddr, sizeof(serverAddr))) { getsockname(socketDescriptor, (struct sockaddr *)&clientAddr, (int*)sizeof(clientAddr)); printf("Local address: %s:%d of server:\n", inet_ntoa(serverAddr.sin_addr), ntohs(serverAddr.sin_port)); FD_ZERO(&writeSet); FD_SET(socketDescriptor, &writeSet); if ((retVal = select(socketDescriptor + 1, NULL, &writeSet, NULL, &tv)) == SOCKET_ERROR) { printf("Send non-blocking error "); break; } else if (retVal == 0) { printf("Non-blocking connect time limit is expired"); break; } } printf("Connection with %s\n", SERVERADDR); while (1) { FD_ZERO(&readSet); FD_ZERO(&writeSet); FD_SET(socketDescriptor, &readSet); FD_SET(socketDescriptor, &writeSet); if ((retVal = select(socketDescriptor + 1, &readSet, &writeSet, NULL, &tv)) == SOCKET_ERROR) { printf("Select error "); break; } else if (retVal == 0) { printf("Time limit is expired "); continue; } char *testmsg = "Hello, I'm a new user online\n"; printf("Client -> Server: "); fgets(&bufferData[0], sizeof(bufferData), stdin); if (FD_ISSET(socketDescriptor, &writeSet) != 0) { //send(socketDescriptor, testmsg, strlen(testmsg), 0); if (send(socketDescriptor, &bufferData[0], strlen(&bufferData[0]), 0) == SOCKET_ERROR) { printf("Send error "); break; } } if (FD_ISSET(socketDescriptor, &readSet) != 0) { if ((numBytes = recv(socketDescriptor, &bufferData[0], MAXDATASIZE, 0)) == SOCKET_ERROR) { printf("Recv error "); break; } bufferData[numBytes] = '\0'; printf("Server -> Client: %s\n", &bufferData[0]); } } } while (FALSE); printf("- Error code: %d\n", WSAGetLastError()); closesocket(socketDescriptor); WSACleanup(); return 0; }
Спасибо за любую помощь