Skip to content

Commit

Permalink
fix windows serialport message duplicate send bug
Browse files Browse the repository at this point in the history
  • Loading branch information
ruanshudong committed Dec 23, 2024
1 parent f0bf2f2 commit 060f28e
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 17 deletions.
4 changes: 4 additions & 0 deletions util/include/util/tc_serialport.h
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,8 @@ class UTIL_DLL_API TC_SerialPort

OVERLAPPED *getOsWrite() { return &_osWrite; }

OVERLAPPED *getOsNotifyWrite() { return &_osNotifyWrite; }

void sendSucc(uint32_t len);

void recvSucc(uint32_t len);
Expand Down Expand Up @@ -411,6 +413,8 @@ class UTIL_DLL_API TC_SerialPort

OVERLAPPED _osWrite;

OVERLAPPED _osNotifyWrite;

list<std::shared_ptr<TC_NetWorkBuffer::Buffer>> _buffRecv;

#else
Expand Down
53 changes: 36 additions & 17 deletions util/src/tc_serialport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,36 +132,41 @@ vector<string> TC_SerialPortGroup::getComPorts(const string &prefix)

void TC_SerialPortGroup::run()
{
int64_t lastHeartbeat = 0;

#if !TARGET_PLATFORM_WINDOWS
_epoller.idle([&]
{
std::lock_guard<std::mutex> lock(_mutex);
for (const auto &e: _serialPorts)
{
e.second->doRequest();

auto callback = e.second->getRequestCallbackPtr();

if(callback)
if(TC_Common::now2ms() - lastHeartbeat > _heartbeatMaxInterval)
{
try { callback->onHeartbeat(); } catch(const std::exception& ex) { }
lastHeartbeat = TC_Common::now2ms();
auto callback = e.second->getRequestCallbackPtr();

if(callback)
{
try { callback->onHeartbeat(); } catch(const std::exception& ex) { }
}
}

e.second->doRequest();
}
});

_epoller.loop(_heartbeatMaxInterval);
_epoller.loop(10);

#else

BOOL bRet;
DWORD dwNumberOfBytesTransferred = 0;
DWORD dwCompletionKey = 0;
OVERLAPPED *opOverlapped = nullptr;
int64_t lastHeartbeat = 0;

while(true)
{
bool bFlag = GetQueuedCompletionStatus(_ioPort, &dwNumberOfBytesTransferred, (PULONG_PTR)(void*)&dwCompletionKey, &opOverlapped, 10);
bool bFlag = GetQueuedCompletionStatus(_ioPort, &dwNumberOfBytesTransferred, (PULONG_PTR)(void*)&dwCompletionKey, &opOverlapped, 1);

if(bFlag && dwCompletionKey == -1)
{
Expand Down Expand Up @@ -199,15 +204,14 @@ void TC_SerialPortGroup::run()
}
else if(opOverlapped == e.second->getOsWrite())
{
if(dwNumberOfBytesTransferred == 0)
{
e.second->doRequest();
}
else
if(dwNumberOfBytesTransferred > 0)
{
e.second->sendSucc(dwNumberOfBytesTransferred);
}

}
else if(opOverlapped == e.second->getOsNotifyWrite())
{
e.second->doRequest();
}
}
e.second->handleInputImp();
Expand Down Expand Up @@ -282,6 +286,12 @@ void TC_SerialPort::close()
_osWrite.hEvent = NULL;
}

if(_osNotifyWrite.hEvent != NULL)
{
CloseHandle(_osNotifyWrite.hEvent);
_osNotifyWrite.hEvent = NULL;
}

if(_serialFd != INVALID_HANDLE_VALUE)
{

Expand Down Expand Up @@ -316,8 +326,10 @@ void TC_SerialPort::initialize()

memset(&_osRead, 0, sizeof(OVERLAPPED));
memset(&_osWrite, 0, sizeof(OVERLAPPED));
memset(&_osNotifyWrite, 0, sizeof(OVERLAPPED));
_osRead.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
_osWrite.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
_osNotifyWrite.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );

COMMTIMEOUTS CommTimeOuts;
CommTimeOuts.ReadIntervalTimeout = 0xFFFFFFFF;
Expand Down Expand Up @@ -586,7 +598,7 @@ void TC_SerialPort::addSendReqBuffer(const shared_ptr<TC_NetWorkBuffer::Buffer>

//发送消息, 唤醒网络线程
#if TARGET_PLATFORM_WINDOWS
PostQueuedCompletionStatus(_serialPortGroup->getIoPort(), 0, 0, &_osWrite);
PostQueuedCompletionStatus(_serialPortGroup->getIoPort(), 0, 0, &_osNotifyWrite);
#else
_serialPortGroup->getEpoller().notify();
#endif
Expand Down Expand Up @@ -926,11 +938,12 @@ int TC_SerialPort::send(const void *buf, uint32_t len)
{
return 0;
}

if(len == 0)
{
return 0;
}

unsigned long dwBytesWritten = 0;
bool bWriteStat = WriteFile(_serialFd, buf, len, &dwBytesWritten, &_osWrite);
bool isPending = TC_Socket::isPending() ;
Expand All @@ -943,6 +956,12 @@ int TC_SerialPort::send(const void *buf, uint32_t len)
throw TC_SerialPortException("TC_SerialPort::send, fd:" + TC_Common::tostr(fd) + ", error:" + err);
}

if(isPending)
{
// 认为发送了,发送多少数据等ioport的通知
return len;
}

return dwBytesWritten;
#else
int iRet = ::write(_serialFd, (const char *) buf, len);
Expand Down

0 comments on commit 060f28e

Please sign in to comment.