在我的一个解析程序中,我必须执行以下操作(在C,C ++,VC ++中): -
我必须通过套接字编程连接100台机器(透析机)。 向每台机器发送请求并从机器接收响应以及我将从机器获得的数据我将必须解析该数据并将值写入文件中。我必须在每5秒后将请求发送到每台机器
所以为了完成上述任务,我想这样做: -
我将从数据库中读取每台机器的ip和端口,创建一个连接到每台机器的线程,并在每个线程中创建一个子线程(子线程),它将发送和接收并解析来自每5秒钟后机器(并在txt文件中写入值)。 我的解析功能很常见。
这是可行的解决方案吗? 请帮帮我。提前告诉我。
答案 0 :(得分:4)
除了一点之外,你的解决方案听起来很合理。您提到您将创建一个连接到每台计算机的线程,然后创建一个子线程来管理发送,接收和解析。我不明白为什么你需要创建一个子线程。您应该能够处理连接线程中的所有内容。还要考虑每个连接1个线程可能无法很好地扩展,如果此应用程序必须处理大量机器,则应避免每台机器的线程。
甚至可以通过简单的线程池来实现这一点,而不是每个连接1个线程,这不会很好地扩展。您可以考虑创建每5秒放置一个工作队列的任务,并且线程池将连接,读取,断开连接,解析和处理。假设这是TCP / IP,您可能不应该保持连接打开,而是为每次读取连接/断开连接,类似于HTTP。
Here是一个与vc ++线程池相关的问题。 here是一些更相关的信息。
另一种选择可能是使用libevent进行套接字通信。至于解析,还有其他库可以使用,如Apache Thrift或JSon,所有这些都是开源的。这些解析库的缺点是您可能还必须修改透析机,这可能不是一个选项。如果您可以使用像Thrift这样的东西,您可以从一个库获取所有内容:socket comm和parsing。
以下是每个连接1个线程的简单情况的一些代码:
class ThreadInfo
{
public:
ThreadInfo(const string &ipAddress, uint16_t port) : ipAddress_(ipAddress), port_(port) {}
string getIpAddress() {return ipAddress_;}
uint16_t getPort() {return port_;}
string getRecvBuffer() {return recvBuffer_;}
private:
string ipAddress_;
uint16_t port_;
string recvBuffer_;
};
void *threadEntryPoint(void *userData)
{
ThreadInfo *threadInfo = (ThreadInfo*) userData;
// You need to decide if you want to keep the connection open while sleeping
// or open and close it for each transaction. Change code here accordingly.
// Create socket with threadInfo->getIpAddress() and threadInfo->getPort()
// while(1)
// Send request to each machine
// Get response from each machine and store in threadInfo->getRecvBuffer()
// The buffer could also be a local var in this function, decide accordingly
// parse data accordingly
// sleep 5 seconds
}
uint16_t getPort(int machineNum) { return 3456; }
string getIpAddress(int machineNum) { return string("192.168.1.2"); }
int main(int argc, char **argv)
{
// 3 items that we need, and that you will have to plugin accordingly:
// 1) Num threads, assuming 100 for now
// 2) IP address of each external machine, implement getIpAddress() accordingly
// 3) port of each machine, implement getPort() accordingly
int numThreads(100);
list<pthread_t> threadIdList;
for(int i = 0; i < numThreads; ++i)
{
pthread_t threadId;
ThreadInfo *threadInfo = new ThreadInfo(getIpAddress(i), getPort(i));
pthread_create(&threadId, NULL, threadEntryPoint, threadInfo);
threadIdList.push_back(threadId);
}
// Wait for the threads to finish
std::list<pthread_t>::iterator iter = threadIdList.begin();
while(iter != threadIdList.end())
{
pthread_t threadId = *iter++;
pthread_join(threadId, NULL);
}
}
答案 1 :(得分:1)
对于100台机器,每5秒轮询一次,每台机器一个线程是合理的 - 线程将在Sleep(5000)上被阻塞大部分时间并且在套接字I / O或磁盘I / O上被阻塞剩下的大部分时间。对于这种加载,(甚至是加载的五倍),我认为没有必要求助于异步I / O或线程池 - 为什么不必要地使问题复杂化?
正如@Brady指出的那样,我不明白为什么每个连接需要多个线程,假设需求是你发布的 - 只需每5秒轮询一次并将回复写入文本文件。
我猜测,(希望:),5秒间隔不是安全关键的实时要求,并且由于某些临时软件,如果周期偶尔为6秒,透析机将继续正常运行或网络延迟。我不是血液学家/肾病专家,但是如果任何透析机器能够对整体治疗做出任何重大改变(这需要数小时),如果民意调查/指示偶尔会延迟一段时间,我会感到惊讶。
编辑 - 重新。 '解析函数并将数据写入文件函数对于所有线程都是通用的' - 应该没问题,假设每台机器都有不同的文本文件。如果日志都写入了一个日志文件,那就更有问题了 - 每个日志条目应该排队到一个记录器线程,单独写入日志文件。使用已经支持此类功能的现有成熟记录器框架将是最简单的解决方案。
答案 2 :(得分:0)
如果你对网络和磁盘IO都使用boost::asio框架,你可能会得到的线程远远少于每台机器要处理的线程。
另外,它有一个很好的高级接口用于套接字编程。