//--------------------------------------------------------------------------- #include "SocketPort.h" //--------------------------------------------------------------------------- #if defined(_WIN32) || defined(_WINDOWS) #include //#include #include //#include #pragma comment(lib, "Ws2_32.lib") #pragma comment(lib, "Mswsock.lib") #pragma comment(lib, "AdvApi32.lib") #else #endif //--------------------------------------------------------------------------- SocketPort::SocketPort() { //id = 0; bOpen = false; my_sock=0; } //------------------------------------------------------------------------------ SocketPort::~SocketPort() { //Close(); } //------------------------------------------------------------------------------ //#define PORT 666 //#define SERVERADDR "*.*.*.*" //Звёздочками пометил свой IP //------------------------------------------------------------------------------ bool SocketPort::Open(const char* IPAddress,int PortNo) { if (bOpen) Close(); #if defined(_WIN32) || defined(_WINDOWS) WORD wVersionRequested; WSADATA wsaData; int err; //Шаг 1 - инициализация wVersionRequested = MAKEWORD(2, 2); err = WSAStartup(wVersionRequested, &wsaData); if(err) { printf("WSAStart error %d\n", WSAGetLastError()); bOpen = false; return bOpen; } // Шаг 2 - создание сокета my_sock = socket(AF_INET, SOCK_STREAM, 0); if (my_sock < 0) { printf("Socket() error %d\n", WSAGetLastError()); bOpen = false; return bOpen; } //Отключаю буферизацию для маленьких пакетов, алгоритм Нейгла 200 миллисекунд DWORD value = 1; if (setsockopt(my_sock, IPPROTO_TCP, TCP_NODELAY, (char*)&value, sizeof(value)) != 0){ printf("setsockopt() error %d\n", WSAGetLastError()); bOpen = false; return bOpen; } //Задаю таймаут для чтения из сокета в миллисекундах те. *1000 (Ниже есть отдельная функция для этого) DWORD timeout = 1 * 1000; if(setsockopt(my_sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout))!=0) { printf("setsockopt() error %d\n", WSAGetLastError()); bOpen = false; return bOpen; } // Шаг 3 - установка соединения // заполнение структуры sockaddr_in - указание адреса и порта сервера sockaddr_in dest_addr; dest_addr.sin_family = AF_INET; dest_addr.sin_port = htons(PortNo); HOSTENT *hst; // преобразование IP адреса из символьного в сетевой формат if (inet_addr(IPAddress) != INADDR_NONE) dest_addr.sin_addr.s_addr = inet_addr(IPAddress); else { //Новая функция на замен gethostbyname /* struct addrinfo hints = { 0 }, * addrs; int err = getaddrinfo(IPAddress, PortNo, &hints, &addrs); if (err == 0) { // hst->h_addr_list содержит не массив адресов, // а массив указателей на адреса ((unsigned long*)&dest_addr.sin_addr)[0] = ((unsigned long**)hst->h_addr_list)[0][0]; freeaddrinfo(addrs); } else { printf("Invalid address %s\n", IPAddress); closesocket(my_sock); WSACleanup(); bOpen = false; return bOpen; }*/ // попытка получить IP адрес по доменному имени сервера hst = gethostbyname(IPAddress); if (hst!=NULL) // hst->h_addr_list содержит не массив адресов, // а массив указателей на адреса ((unsigned long *)&dest_addr.sin_addr)[0] = ((unsigned long **)hst->h_addr_list)[0][0]; else { printf("Invalid address %s\n", IPAddress); closesocket(my_sock); WSACleanup(); bOpen = false; return bOpen; } } // адрес сервера получен - пытаемся установить соединение if (connect(my_sock, (sockaddr *)&dest_addr, sizeof(dest_addr))) { printf("Connect error %d\n", WSAGetLastError()); bOpen = false; return bOpen; } //printf("Soedinenie s %s uspeshno ustanovlenno\n \ Type quit for quit\n\n", IPAddress); bOpen = true; #else struct sockaddr_in server; //Create socket my_sock = socket(AF_INET , SOCK_STREAM , 0); if (my_sock == -1) { printf("Could not create socket"); } puts("Socket created"); server.sin_addr.s_addr = inet_addr(IPAddress); server.sin_family = AF_INET; server.sin_port = htons( PortNo ); //Connect to remote server if (connect(my_sock , (struct sockaddr *)&server , sizeof(server)) < 0) { perror("connect failed. Error"); return 1; } puts("Connected\n"); #endif return true; } //------------------------------------------------------------------------------ //Сколько ждать данных в миллисекундах при чтении данных bool SocketPort::SetTimeout(unsigned long time) { #if defined(_WIN32) || defined(_WINDOWS) DWORD timeout = time; if(setsockopt(my_sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout))!=0) { return false; } #else struct timeval tv; tv.tv_sec = time/1000; tv.tv_usec = (time%1000)*1000; int result=setsockopt(my_sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); if(result!=0) { return false; } result=setsockopt(my_sock, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)); if(result!=0) { return false; } #endif return true; } //------------------------------------------------------------------------------ bool SocketPort::Close() { #if defined(_WIN32) || defined(_WINDOWS) if (my_sock) closesocket(my_sock); //WSACleanup(); Закоментил так как сокеты могут использоваться во многих местах #else shutdown(my_sock,2); close(my_sock); #endif bOpen = false; return true; } //------------------------------------------------------------------------------ unsigned long SocketPort::Write(const void* lpBuffer,unsigned long nNumberOfBytesToWrite) { return send(my_sock,(const char*)lpBuffer,nNumberOfBytesToWrite,0); } //------------------------------------------------------------------------------ unsigned char SocketPort::WriteChar(signed char ch) { return (unsigned char)Write(&ch,1); } //------------------------------------------------------------------------------ unsigned char SocketPort::WriteUChar(unsigned char ch) { return (unsigned char)Write(&ch,1); } //------------------------------------------------------------------------------ unsigned char SocketPort::WriteUInt(unsigned int val) { return (unsigned char)Write(&val,4); } //------------------------------------------------------------------------------ //Для MQTT протокола int SocketPort::writeUTF8(std::string str) { if(str.length()>=65535) return 0; unsigned short size=str.length(); int len=0; len+=WriteUChar(((uint8_t*)&size)[1]); len+=WriteUChar(((uint8_t*)&size)[0]); len+=Write(str.c_str(),str.length()); return len; } //------------------------------------------------------------------------------ //Читать столько сколько за раз придёт int SocketPort::Read(void* lpBuffer,unsigned long nNumberOfBytesToRead) { if(nNumberOfBytesToRead<=0) return 0; return recv(my_sock,(char*)lpBuffer,nNumberOfBytesToRead,0); } //------------------------------------------------------------------------------ //Попытаться и заполнить весь буфер //Результат количество прочитанных байт int SocketPort::ReadAll(void* lpBuffer,unsigned long nNumberOfBytesToRead) { if(nNumberOfBytesToRead==0) return 0; int len; int pos=0; while(true){ len=recv(my_sock,&((char*)lpBuffer)[pos],nNumberOfBytesToRead,0); if(len==-1) break; if(len==0) break; pos+=len; nNumberOfBytesToRead-=len; if(nNumberOfBytesToRead==0) break; } return pos; } //------------------------------------------------------------------------------ //Прочитать и изменить порядок байт int SocketPort::ReadR(void* lpBuffer,unsigned long nNumberOfBytesToRead) { if(nNumberOfBytesToRead==0) return 0; int result=recv(my_sock,(char*)lpBuffer,nNumberOfBytesToRead,0); if(result>1){ char ch; int d=result/2; for(int i=0;i