I have a file that is larger than 512 bytes to send to an esp32. I'm sending "withoutResponse: false", the flutter_blue library does the split according to the mtu size without problems, but when it reaches 512 bytes it returns an error to write in characteristic. To solve this I have a function that splits the file and writes each 512 bytes.
Esp32 can send me files larger than 512 without doing anything. Can I send larger files without splitting?
Example of code or library that makes this possible
ok, I decided to switch to the flutter_reactive_ble library, and I developed code similar to this one. Basically I split the file into smaller packets of 4096 bytes (this was defined in my communication protocol with esp32), then I call the function that sends and it splits again the file into packets the size of mtu less 19 bytes that are from the header. In the last packet I "writeWithResponse" and wait for the response, if it responds ok, increment and send the next package and repit the processs until the end of file.
late StreamSubscription<List<int>>? subscribeStream;
List<int> bytesOfFile = [];
int _size = 0;
int _increment = 0;
List<int> _returnOfSubscribe = [];
int _indexOfUploadController = 0;
Future<void> subscribeCharacteristic() async {
subscribeStream = widget
.subscribeToCharacteristic(widget.rcharacteristic)
.listen((event) {
debugPrint("resposta${hexToString(event)}");
setState(() {
_returnOfSubscribe = event;
if (_returnOfSubscribe != 'code of confirm reception file') {
debugPrint('err');
} else {
_increment++;
actualize();
}
});
});
}
void actualize() async {
int splitSize = 4096;
Iterable<int> s;
int n = (bytesOfFile.length / splitSize).ceil();
//if is the last split
if (_increment >= n) {
if (_returnOfSubscribe == 'code of confirm end of file') {
debugPrint("success");
} else {
debugPrint("err");
}
return;
}
if ((_size + splitSize) < bytesOfFile.length) {
s = bytesOfFile.getRange(_size, _size + splitSize);
} else {
s = bytesOfFile.getRange(_size, bytesOfFile.length);
}
await writeLongData(s.toList());
_size += splitSize;
}
writeLongData(List<int> data) async {
int splitSize = mtuNotifier.value - 19;
Iterable<int> s;
int size = 0;
int n = (data.length / splitSize).ceil();
for (int i = 0; i < n; i++) {
if ((size + splitSize) < data.length) {
s = data.getRange(size, size + splitSize);
} else {
s = data.getRange(size, data.length);
}
try {
if ((size + splitSize) < data.length) {
await widget.writeWithoutResponse(widget.wcharacteristic, s.toList());
} else {
//if the last, write with response
await widget.writeWithResponse(widget.wcharacteristic, s.toList());
}
} catch (e) {
debugPrint('$e');
return;
}
size += splitSize;
}
}
I have written a very simple code for client side of a socket.
this is my receive function:
int n32RecvLength = 10;
do {
n32RecvLength = recv(m_socketConnectSocket, m_szRecvBuffer, m_n32BufferLength, MSG_WAITALL);
if ( n32RecvLength > 0 )
{
printf("\nBytes received: %d\n", n32RecvLength);
//for(int i = 0; i< n32RecvLength; i++)
//putchar(m_szRecvBuffer[i]);
if (evRecPacket != NULL)
{
evRecPacket(static_cast<void*>(m_ptrvDerivedClass),reinterpret_cast<unsigned char*>(m_szRecvBuffer) , n32RecvLength);
}
}
else if ( n32RecvLength == 0 )
{
printf("Connection closed!!!!!!!\n");
if(evDisconnected != NULL)
evDisconnected(static_cast<void*>(m_ptrvDerivedClass));
break;
}
else
{
int errorNum = WSAGetLastError();
if (errorNum == WSAETIMEDOUT)
{
printf ("\n timeOut\n");
n32RecvLength = 1;
}
else
{
printf("recv failed with error: %d\n", errorNum);
if(evDisconnected != NULL)
evDisconnected(static_cast<void*>(m_ptrvDerivedClass));
break;
}
}
} while( n32RecvLength > 0 );
and I have initialized it in this function:
WSADATA swsaData;
struct addrinfo *result = NULL;
struct addrinfo hints;
unsigned int n32CheckCondition = 0;
n32CheckCondition = WSAStartup(MAKEWORD(2,2), &swsaData);
if (n32CheckCondition != 0) {
printf("WSAStartup failed with error: %d\n", n32CheckCondition);
return;
}
ZeroMemory( &hints, sizeof(hints) );
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
char szPortNumber[100];
itoa(m_n32PortNumber,szPortNumber , 10);
n32CheckCondition = getaddrinfo(m_szIpServerAddr, szPortNumber, &hints, & m_ptrsResult);
if ( n32CheckCondition != 0 ) {
printf("getaddrinfo failed with error: %d\n", n32CheckCondition);
WSACleanup();
return;
}
m_socketConnectSocket = socket( m_ptrsResult->ai_family, m_ptrsResult->ai_socktype, m_ptrsResult->ai_protocol);
if (m_socketConnectSocket == INVALID_SOCKET)
{
printf("socket failed with error: %ld\n", WSAGetLastError());
WSACleanup();
return;
}
// to set timeout feature to your system, uncomment the two following lines and adjust it
DWORD timeout = 10000; // mili second!
setsockopt(m_socketConnectSocket, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout));
I am using recv function with MSG_WAITALL flag. I have set the timeout = 10000 milliseconds.
I have set the m_n32BufferLength = 8. when I send a 8-byte data, it works fine, but when I send 9 byte it shows first 8 bytes and after a few second (timeout value) the recv(...) returns zero. I know when recv returns zero, it means that socket has been closed. but I have not closed the socket. and I also loss the 9th byte of my data.
could you please tell me what I should do?
I have writen an IOCP program and I am testing it through VPN.
It was all working OK, but then the server disconnected and the client GetQueuedCompletionStatus didn't trigger an exception.
I waited for one day,cbut it didn't get better. When I changed to a new VPN, the problem was solved, and I didn't get that problem later.
What's wrong? Has anybody seen the same problem before?
enter code here
enter code here
#include "XYTransport.h"
//---------------------------------------------------------------------------
#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x))
#define FREE(x) HeapFree(GetProcessHeap(), 0, (x))
//---------------------------------------------------------------------------
#define XYTCP_LIST_CLIENT0 0
#define XYTCP_LIST_CLIENT1 1
//---------------------------------------------------------------------------
#define XYTRANSPORT_TYPE_TCP_OPEN 0
#define XYTRANSPORT_TYPE_TCP_RECV 1
#define XYTRANSPORT_TYPE_TCP_SEND 2
//---------------------------------------------------------------------------
typedef struct tagXYOVERLAPPED
{
OVERLAPPED o;
SOCKET s;
UINT flags;
WSABUF wb;
}XYOVERLAPPED, *PXYOVERLAPPED;
//---------------------------------------------------------------------------
inline LPVOID XYAlloc(HANDLE heap, UINT size)
{
return(HeapAlloc(heap, 0, size));
}
inline VOID XYFree(HANDLE heap, LPVOID lpdata)
{
HeapFree(heap, 0, lpdata);
}
inline PXYOVERLAPPED XYOverlappedPop(PXYTRANSPORT pt, LPBYTE buffer, SOCKET s)
{
PXYOVERLAPPED pto = NULL;
SOCKADDR_IN name;
if (buffer == NULL)
{
buffer = (LPBYTE)VirtualAlloc(NULL, pt->bufferlength, MEM_COMMIT, PAGE_READWRITE);
}
if (buffer != NULL)
{
pto = (PXYOVERLAPPED)MALLOC(sizeof(XYOVERLAPPED));
if (pto != NULL)
{
pto->wb.buf = (char *)buffer;
pto->wb.len = pt->bufferlength;
if (s == INVALID_SOCKET)
{
pto->s = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);
if (pto->s != INVALID_SOCKET)
{
ZeroMemory(&name, sizeof(name));
name.sin_family = AF_INET;
name.sin_addr.S_un.S_addr = INADDR_ANY;
//name.sin_port = fn_htons(0);
name.sin_port = 0;
if (bind(pto->s, (const SOCKADDR *)&name, sizeof(name)) == 0)
{
if (CreateIoCompletionPort((HANDLE)pto->s, pt->hcompletion, (ULONG_PTR)pto->s, 0) == pt->hcompletion)
{
//
}
}
}
}
else
{
pto->s = s;
}
}
}
return(pto);
}
BOOL XYTCPPushReceive(PXYTRANSPORT pt, PXYOVERLAPPED pto, SOCKET s)
{
DWORD numberofbytes;
DWORD flags = 0;
BOOL result;
int error;
if (pto == NULL)
{
pto = XYOverlappedPop(pt, NULL, s);
}
ZeroMemory(&pto->o, sizeof(OVERLAPPED));
pto->flags = XYTRANSPORT_TYPE_TCP_RECV;
result = WSARecv(pto->s, &pto->wb, 1, &numberofbytes, &flags, &pto->o, NULL) != SOCKET_ERROR;
if (!result)
{
error = WSAGetLastError();
result = error == WSA_IO_PENDING;
if (!result)
{
printf("WSARecv\n");
}
}
return(result);
}
inline BOOL XYTCPPushSend(PXYTRANSPORT pt, PXYOVERLAPPED pto)
{
DWORD numberofbytes;
ULONG flags = MSG_PARTIAL;
BOOL result;
int error;
ZeroMemory(&pto->o, sizeof(OVERLAPPED));
pto->flags = XYTRANSPORT_TYPE_TCP_SEND;
//
pto->wb.len = 1024;
//
result = WSASend(pto->s, &pto->wb, 1, &numberofbytes, flags, &pto->o, NULL) != SOCKET_ERROR;
if (!result)
{
error = WSAGetLastError();
result = error == WSA_IO_PENDING;
if (!result)
{
printf("Send Error\n");
}
}
return(result);
}
DWORD WINAPI XYTransportWorkProc(LPVOID parameter)
{
PXYTRANSPORT pt = (PXYTRANSPORT)parameter;
HANDLE hcompletion = pt->hcompletion;
LPOVERLAPPED po;
PXYOVERLAPPED pto;
ULONG_PTR completionkey;
DWORD numberofbytes;
SOCKET s;
BOOL flag;
UINT type;
UINT count;
UINT error;
while(pt->working)
{
flag = GetQueuedCompletionStatus(hcompletion, &numberofbytes, &completionkey, &po, INFINITE);
if (po != NULL)
{
pto = (PXYOVERLAPPED)CONTAINING_RECORD(po, XYOVERLAPPED, o);
s = (SOCKET)completionkey;
type = pto->flags;
if (!flag)
{
//OutputDebugValue(_T("Except Error"), type, numberofbytes);
printf("Except Error %d\n", type);
}
if (numberofbytes == 0)
{
//OutputDebugValue(_T("Length Error"), type);
printf("Length Error %d\n", type);
}
if (!flag)
{
numberofbytes = 0;
}
switch (type)
{
case XYTRANSPORT_TYPE_TCP_OPEN:
if (flag)
{
setsockopt(s, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, NULL, 0);
XYTCPPushSend(pt, pto);
printf("connected\n");
if (!XYTCPPushReceive(pt, NULL, s))
{
//
}
else
{
printf("post recv\n");
}
break;
}
break;
case XYTRANSPORT_TYPE_TCP_RECV:
if (numberofbytes > 0)
{
XYTCPPushReceive(pt, pto, s);
//OutputDebugString(_T("Recv"));
printf("Recv %d\n", numberofbytes);
}
else
{
printf("Recv Error\n");
}
break;
case XYTRANSPORT_TYPE_TCP_SEND:
if (numberofbytes > 0)
{
XYTCPPushSend(pt, pto);
printf("Send %d\n", numberofbytes);
}
else
{
printf("Send Except\n");
}
break;
default:
break;
}
}
else
{
printf("Quit %d, %d", GetCurrentThreadId(), flag);
break;
}
}
return(0);
}
VOID XYTransportStartup(PXYTRANSPORT pt, UINT pagesize)
{
pt->hcompletion = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1);
if (pt->hcompletion != INVALID_HANDLE_VALUE)
{
pt->lpfnConnectEx = NULL;
pt->bufferlength = pagesize;
pt->working = TRUE;
pt->hthread = CreateThread(NULL, 0, XYTransportWorkProc, (LPVOID)pt, 0, NULL);
}
}
BOOL XYTCPConnect(PXYTRANSPORT pt, const CHAR *host, USHORT port)
{
GUID id = WSAID_CONNECTEX;
DWORD numberofbytes = 0;
PXYOVERLAPPED pto;
SOCKADDR_IN name;
BOOL result = FALSE;
int error;
pto = XYOverlappedPop(pt, NULL, INVALID_SOCKET);
if (pt->lpfnConnectEx != NULL || WSAIoctl(pto->s, SIO_GET_EXTENSION_FUNCTION_POINTER, &id, sizeof(id), &pt->lpfnConnectEx, sizeof(pt->lpfnConnectEx), &numberofbytes, NULL, NULL) != SOCKET_ERROR)
{
ZeroMemory(&pto->o, sizeof(OVERLAPPED));
pto->flags = XYTRANSPORT_TYPE_TCP_OPEN;
ZeroMemory(&name, sizeof(name));
name.sin_family = AF_INET;
name.sin_port = htons(port);
name.sin_addr.S_un.S_addr = inet_addr(host);
if (name.sin_addr.S_un.S_addr != INADDR_NONE)
{
numberofbytes = 0;
result = pt->lpfnConnectEx(pto->s, (SOCKADDR *)&name, sizeof(name), NULL, 0, &numberofbytes, &pto->o);
if(!result)
{
error = WSAGetLastError();
result = error == ERROR_IO_PENDING;
if (!result)
{
printf("ConnectEx error\n");
}
}
}
}
return(result);
}
//---------------------------------------------------------------------------
the client Thrown an exception is what i desired,so i can know.
I am using C language to write. Under normal circumstances, disconnect one end and the other end will trigger an exception, but I have found that sometimes have to wait a very long time, at least I'm waiting for more than one day are not triggered, and sometimes even in the off time can continue to deliver WSASend success for some time.
I am reading a value sent over RS485 which is the value of an encoder I first check if it has returned an E character (the encoder is reporting an error) and if not then do the following
*position = atoi( buffer );
// Also tried *position = (s32) strtol(buffer,NULL,10);
The value in the buffer is 4033536 and position gets set to 33536 this does not happen every time in this function probably 1 in 1000 times maybe although I am not counting. Setting the program counter back and doing the line again if has failed returns the same result but starting the debugger again causes the value to convert correctly.
I am using keil uvision 4, its a custom board using an stm32f103vet6 and the stm32f10 library V2.0.1 This one has really got me stumped never come across something like this before any help would be much appreciated.
Thanks
As no one knows I will just post what I ended up doing which was to write my own function for convertion not ideal but it worked.
bool cdec2s32(char* text, s32 *destination)
{
s32 tempResult = 0;
char currentChar;
u8 numDigits = 0;
bool negative = FALSE;
bool warning = FALSE;
if(*text == '-')
{
negative = TRUE;
text++;
}
while(*text != 0x00 && *text != '\r') //while current character not null or carridge return
{
numDigits++;
if(*text >= '0' && *text <= '9')
{
currentChar = *text;
currentChar -= '0';
if((warning && ((currentChar > 7 && !negative) || currentChar > 8 && negative )) || numDigits > 10) // Check number not too large
{
tempResult = 2147483647;
if(negative)
tempResult *= -1;
*destination = tempResult;
return FALSE;
}
tempResult *= 10;
tempResult += currentChar;
text++;
if(numDigits >= 9)
{
if(tempResult >= 214748364)
{
warning = TRUE; //Need to check next digit as close to limit
}
}
}
else if(*text == '.' || *text == ',')
{
break;
}
else
return FALSE;
}
if(negative)
tempResult *= -1;
*destination = tempResult;
return TRUE;
}
I am working on a application which involves socket programming. I am trying to implement reset functionality in this application in case server is closed or crashed for any reason. For reset I need to reestablish communication between the client and server after manual restart of server. Now I am able to send request from client to server which server would process and send reply to client. Send() function at server side is returning with success but WSAWaitForMultipleEvents() function at client side is returning with WSA_TIME_OUT every time.
I restart my socket at client side with SO_REUSEADDR true value on reset. I am very new to network programming i am not able to understand why this is happening.
here is my code at client side. Its little messed up so please bear with me
void
SocketListner::run()
{
// std::cout << "Thread ID of SocketListener : " << QThread::currentThreadId() << "\n";
if(_isFrameGrabber)
{
_listenForFrames();
}
else
{
_listenForRequests();
}
}
void
SocketListner::_listenForRequests()
{
DWORD eventVal;
unsigned int eventSock;
WSANETWORKEVENTS networkEvents;
std::stringstream ss;
int bufferLength = 500;
char * msg = new char[bufferLength];
std::string Msg = "";
int retCode;
int diff;
while(!_done)
{
// Giving it one second less than the condition wait time
// OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_destructorMutex);
if((eventVal=WSAWaitForMultipleEvents(_eventCnt, _socketEvents, false, 3000, false)) == WSA_WAIT_FAILED)
{
ss.str("");
ss << "WSAWaitForMultipleEvents() failed with error : " << WSAGetLastError();
LOG_ERROR(ss.str());
emit socketErrorSignal(eventVal);
break;
}
else if(eventVal == WSA_WAIT_TIMEOUT)
{
//OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
if(_done)
{
WSACloseEvent(_socketEvents[0]);
if(_eventCnt==2)
WSACloseEvent(_socketEvents[1]);
break;
}
continue;
}
if( (diff=(eventVal - WSA_WAIT_EVENT_0)) == 0 )
eventSock = s_sock;
else if(diff == 1)
eventSock = c_sock;
else
continue;
if((WSAEnumNetworkEvents(eventSock, _socketEvents[eventVal - WSA_WAIT_EVENT_0], &networkEvents)) == SOCKET_ERROR)
{
ss.str("");
ss << "WSAEnumNetworkEvents() failed with error : " << WSAGetLastError();
LOG_ERROR(ss.str());
// break;
}
if (networkEvents.lNetworkEvents & FD_ACCEPT)
{
if (networkEvents.iErrorCode[FD_ACCEPT_BIT] != 0)
{
ss.str("");
ss << "FD_ACCEPT failed with error : " << networkEvents.iErrorCode[FD_ACCEPT_BIT];
LOG_ERROR(ss.str());
break;
}
if ((c_sock = accept(eventSock, NULL, NULL)) == INVALID_SOCKET)
{
ss.str("");
ss << "accept() failed with error : " << WSAGetLastError();
LOG_ERROR(ss.str());
break;
}
if ((_socketEvents[_eventCnt] = WSACreateEvent()) == WSA_INVALID_EVENT)
{
std::stringstream ss;
ss << "WSACreateEvent() failed with error : " << WSAGetLastError();
LOG_ERROR(ss.str());
break;
}
if( WSAEventSelect(c_sock, _socketEvents[_eventCnt], FD_READ | FD_CLOSE) == SOCKET_ERROR)
{
ss.str("");
ss << "WSAEventSelect() failed with error : " << WSAGetLastError();
LOG_ERROR(ss.str());
break;
}
++_eventCnt;
}
if(networkEvents.lNetworkEvents & FD_READ)
{
if (networkEvents.lNetworkEvents & FD_READ && networkEvents.iErrorCode[FD_READ_BIT] != 0)
{
ss.str("");
ss << "FD_READ failed with error : " << networkEvents.iErrorCode[FD_READ_BIT];
LOG_ERROR(ss.str());
}
if((retCode = recv(eventSock, msg, bufferLength, 0)) > 0)
{
int place = 0;
while(place < retCode)
{
if(msg[place] == '\n' && Msg.length() != 0)
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
//Naresh: Replacing std::vector by std::queue
_requests.push(Msg);
Msg = "";
}
else
{
if(msg[place] != '\0')
Msg.push_back(msg[place]);
}
++place;
}
}
//Abhishek: Testing Complete else block
else if(retCode == 0 || WSAGetLastError() == WSAECONNRESET)
{
//Abhishek
shutdown(c_sock, SD_BOTH);
shutdown(s_sock, SD_BOTH);
closesocket(c_sock);
closesocket(s_sock);
int error = WSAGetLastError();
if(!_initialize())
{
_done = true;
return;
}
}
else if(retCode == SOCKET_ERROR)
{
bool stopListening=false;
int errorCode = WSAGetLastError();
_processSocketError(errorCode, stopListening);
if(stopListening)
{
LOG_WARNING("Connection with the partner lost.");
emit socketErrorSignal(errorCode);
break;
}
}
}
if(networkEvents.lNetworkEvents & FD_CLOSE)
{
if (networkEvents.iErrorCode[FD_CLOSE_BIT] != 0)
{
ss.str("");
ss << "FD_CLOSE failed with error : " << networkEvents.iErrorCode[FD_CLOSE_BIT];
LOG_ERROR(ss.str());
emit socketErrorSignal(networkEvents.iErrorCode[FD_CLOSE_BIT]);
}
else if(!_stopped)
{
LOG_ERROR("Lost Connection with Wall.");
emit socketErrorSignal(networkEvents.iErrorCode[FD_CLOSE_BIT]);
}
closesocket(eventSock);
break;
}
//Sleep(100);
} //While
delete[] msg;
msg = NULL;
// If any failure occurs make the _bDone variable to true, as thread is no longer running
_cleanUpCondition.signal();
}
here is _initialize function
bool
SocketListner::_initialize()
{
if(_IP.length() <= 0)
{
LOG_ERROR("Host IP Address : " + _IP + " is invalid.");
return false;
}
//Naresh: replacing vector by queue
while(!_requests.empty())
{
_requests.pop();
}
WSADATA wsaData;
if(WSAStartup(0x101,&wsaData) != 0)
{
LOG_ERROR("Failed WSAStartUp() call.");
return false;
}
sockaddr_in SockAddr;
SockAddr.sin_family = AF_INET;
SockAddr.sin_port = htons(_port);
SockAddr.sin_addr.s_addr = inet_addr(_IP.c_str());
s_sock = socket(AF_INET,SOCK_STREAM,0);
//Abhishek:BugFix for reset enable address reuse else bind() will fail
bool addrReuse = true;
setsockopt(s_sock, SOL_SOCKET, SO_REUSEADDR, (const char*) &addrReuse, sizeof(BOOL));
if(!_isFrameGrabber)
{
if ((_socketEvents[_eventCnt] = WSACreateEvent()) == WSA_INVALID_EVENT)
{
std::stringstream ss;
ss << "WSACreateEvent() failed with error : " << WSAGetLastError();
LOG_ERROR(ss.str());
return false;
}
if(WSAEventSelect(s_sock, _socketEvents[_eventCnt], FD_ACCEPT | FD_CLOSE)== SOCKET_ERROR)
{
std::stringstream ss;
ss << "WSAEventSelect() failed with error : " << WSAGetLastError();
LOG_ERROR(ss.str());
return false;
}
++_eventCnt;
}
if(s_sock == INVALID_SOCKET)
return false;
int errorCode = bind(s_sock,(sockaddr*)&SockAddr,sizeof(SockAddr));
if(errorCode == SOCKET_ERROR)
{
bool stopListening = false;
_processSocketError(WSAGetLastError(), stopListening);
return false;
}
if(listen(s_sock,10)!=0)
{
return false;
}
return true;
}
If the peer dies there won't necessarily be any events at all. The only reliable way to detect a broken connection in TCP is to write to it. The first write to a broken connection will probably succeed but a later one will fail.
I found the solution to my problem. Now I am restarting all threads and sockets on reset in my application. After that i found server was not able to send because it was not able to connect new socket. I placed a infinite loop for trying to connect to client socket in my sendData() function. Which did the trick for me.