Files
Tools_CPP/devices/SocketPort.cpp
2024-11-01 12:23:13 +05:00

278 lines
8.7 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//---------------------------------------------------------------------------
#include "SocketPort.h"
//---------------------------------------------------------------------------
#if defined(_WIN32) || defined(_WINDOWS)
#include <windows.h>
//#include <minwinbase.h>
#include <winnt.h>
//#include <fileapi.h>
#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<d;i++){
ch=((char*)lpBuffer)[i];
((char*)lpBuffer)[i]=((char*)lpBuffer)[result-i-1];
((char*)lpBuffer)[result-i-1]=ch;
}
}
return result;
}
//------------------------------------------------------------------------------