278 lines
8.7 KiB
C++
278 lines
8.7 KiB
C++
//---------------------------------------------------------------------------
|
||
#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;
|
||
}
|
||
//------------------------------------------------------------------------------
|