[英]TCP Two-Way Communication using Qt
I am trying to setup a TCP communication framework between two computers. 我试图在两台计算机之间设置TCP通信框架。 I would like each computer to send data to the other.
我希望每台计算机都能将数据发送给另一台计算机。 So computer A would perform a calculation, and send it to computer B. Computer B would then read this data, perform a calculation using it, and send a result back to computer A. Computer A would wait until it receives something from computer B before proceeding with performing another calculation, and sending it to computer B.
因此,计算机A将执行计算,并将其发送到计算机B.计算机B然后将读取该数据,使用它执行计算,并将结果发送回计算机A.计算机A将等到它从计算机B接收到某些东西之前继续执行另一次计算,并将其发送到计算机B.
This seems conceptually straightforward, but I haven't been able to locate an example that details two-way (bidirectional) communication via TCP. 这似乎在概念上很简单,但我无法找到一个通过TCP详细说明双向(双向)通信的示例。 I've only found one-way server-client communication, where a server sends data to a client.
我只找到了单向服务器 - 客户端通信,服务器将数据发送到客户端。 These are some examples that I have looked at closely so far:
这些是我到目前为止密切关注的一些例子:
I'm basically looking to have two "servers" communicate with each other. 我基本上希望有两个“服务器”相互通信。 The synchronized approach above is, I believe, important for what I'm trying to do.
我相信上面的同步方法对于我正在尝试做的事情很重要。 But I'm struggling to setup a two-way communication framework via a single socket.
但我正在努力通过单个插槽设置双向通信框架。
I would appreciate it greatly if someone could point me to examples that describe how to setup bidirectional communication with TCP, or give me some pointers on how to set this up, from the examples I have linked above. 如果有人能指出我描述如何设置与TCP的双向通信的示例,或者从我上面链接的示例中给出一些关于如何设置它的指示,我将非常感激。 I am very new to TCP and network communication frameworks and there might be a lot that I could be misunderstanding, so it would be great if I could get some clear pointers on how to proceed.
我对TCP和网络通信框架都很陌生,可能有很多我可能会误解,所以如果我能得到一些关于如何继续的明确指示,那将是很好的。
This answer does not go into specifics , but it should give you a general idea, since that's what you really seem to be asking for. 这个答案没有详细说明 ,但它应该给你一个大致的想法,因为那是你真正想要的。 I've never used Qt before, I do all my networking code with BSD-style sockets directly or with my own wrappers.
我之前从未使用过Qt,我直接使用BSD风格的套接字或使用自己的包装器来完成所有网络代码。
Stuff to think about: 想一想:
'\\0'
, '\\n'
, and "\\r\\n"
. '\\0'
, '\\n'
和"\\r\\n"
。 If the rest of your protocol is also text-based, this means it is much easier to debug. p
versions below include atomic signal mask changing. p
版本包括原子信号掩码更改。 I don't recommend using them; signalfd
to the set or else emulate it using signal handlers and a (nonblocking, be careful!) pipe. signalfd
添加到集合中,要么使用信号处理程序和(非阻塞,小心!)管道来模拟它。 select
/ pselect
is the classic, available everywhere. select
/ pselect
是经典的,随处可用。 Cannot have more than FD_SETSIZE
file descriptors, which may be very small (but can be #define
d on the command-line if you're careful enough. Inefficient with sparse sets. Timeout is microseconds for select
and nanonseconds for pselect
, but chances are you can't actually get that. Only use this if you have no other choice. FD_SETSIZE
文件描述符,这可能非常小(但如果你足够小心,可以在命令行上#define
d。对于稀疏集合效率低。 select
超时为微秒, pselect
超时为纳秒,但机会是你实际上无法做到这一点。只有你别无选择才能使用它。 poll
/ ppoll
solves the problems of sparse sets, and more significantly the problem of listening to more than FD_SETSIZE
file descriptors. poll
/ ppoll
解决了稀疏集的问题,更重要的是收听了超过FD_SETSIZE
文件描述符的问题。 It does use more memory, but it is simpler to use. poll
is POSIX, ppoll
is GNU-specific. poll
是POSIX, ppoll
是GNU特有的。 For both, the API provides nanosecond granularity for the timeout, but you probably can't get that. epoll
's headaches. epoll
的麻烦,我建议这样做。 epoll
solves the problem of having to respecify the file descriptor and event list every time. epoll
解决了每次都必须重新指定文件描述符和事件列表的问题。 by keeping the list of file descriptors. epoll
can immediately be made aware, regardless of whether the user program is already in a syscall or not. epoll
。 Supports edge-triggered mode, but don't use it unless you're sure you understand it. poll
is simpler. poll
更简单。 kqueue
is found on BSD-derived systems, including Mac OS X. It is supposed to solve the same problems as epoll
, but instead of keeping things simple by using file descriptors, it has all sorts of strange structures and does not follow the "do only one thing" principle. kqueue
是在BSD派生系统上找到的,包括Mac OS X.它应该解决与epoll
相同的问题,但不是通过使用文件描述符保持简单,它有各种奇怪的结构,不遵循“做”只有一件事“原则。 I have never used it. O_NONBLOCK
set and also disable Nagle's algorithm (since you're doing buffering yourself), except possibly connect
's before the connection is made, since that requires confusing logic, especially if you want to play nice with multiple DNS results. O_NONBLOCK
集,并禁用Nagle算法(因为你在做缓冲自己),除了可能connect
的是连接之前,因为这需要混乱的逻辑,特别是如果你要玩多个DNS不错结果。 accept
in the listen
ing socket's handler, and read/write
family in the accept
/ connect
ed handler. accept
在listen
荷兰国际集团插座的处理器,和read/write
在家庭accept
/ connect
编辑处理。 For other sorts of sockets, you need the send/recv
family. send/recv
系列。 See the "see also" in their man pages for more info - chances are one of them will be useful to you sometimes, do this before you hard-code too much into your API design. TCP_CORK
might imply a different design, I haven't used it. TCP_CORK
可能意味着不同的设计,但我还没有使用它。 Edit 2019: 编辑2019:
The documentation of D-Bus and 0MQ are worth reading, whether you use them or not. 无论您是否使用,D-Bus和0MQ的文档都值得一读。 In particular, it's worth thinking about 3 kinds of conversations:
特别值得考虑3种对话:
D-Bus in particular makes a lot of decisions that seem quite strange at first, but do have justifications (which may or may not be relevant, depending on the use case). D-Bus特别做出了很多看起来很奇怪的决定,但确实有正当理由(根据用例情况可能相关或不相关)。 Normally, it is only used locally.
通常,它仅在本地使用。
0MQ is lower-level and most of its "downsides" are solved by building on top of it. 0MQ是较低级别的,其大部分“缺点”都是通过构建它来解决的。 Beware of the MxN problem;
小心MxN问题; you might want to artificially create a broker node just for messages that are prone to it.
您可能希望人为地创建一个代理节点,仅用于容易发生的消息。
TCP is inherently bidirectional. TCP本质上是双向的。 Get one way working (client connects to server).
获得一种方式(客户端连接到服务器)。 After that both ends can use send and recv in exactly the same way.
之后,两端都可以完全相同的方式使用send和recv。
#include <QAbstractSocket>
#include <QtNetwork>
#include <QTcpServer>
#include <QTcpSocket>
QTcpSocket* m_pTcpSocket;
Connect to host: set up connections with tcp socket and implement your slots. 连接到主机:使用tcp套接字建立连接并实现您的插槽。 If data bytes are available readyread() signal will be emmited.
如果数据字节可用,则readyread()信号将被激活。
void connectToHost(QString hostname, int port){
if(!m_pTcpSocket)
{
m_pTcpSocket = new QTcpSocket(this);
m_pTcpSocket->setSocketOption(QAbstractSocket::KeepAliveOption,1);
}
connect(m_pTcpSocket,SIGNAL(readyRead()),SLOT(readSocketData()),Qt::UniqueConnection);
connect(m_pTcpSocket,SIGNAL(error(QAbstractSocket::SocketError)),SIGNAL(connectionError(QAbstractSocket::SocketError)),Qt::UniqueConnection);
connect(m_pTcpSocket,SIGNAL(stateChanged(QAbstractSocket::SocketState)),SIGNAL(tcpSocketState(QAbstractSocket::SocketState)),Qt::UniqueConnection);
connect(m_pTcpSocket,SIGNAL(disconnected()),SLOT(onConnectionTerminated()),Qt::UniqueConnection);
connect(m_pTcpSocket,SIGNAL(connected()),SLOT(onConnectionEstablished()),Qt::UniqueConnection);
if(!(QAbstractSocket::ConnectedState == m_pTcpSocket->state())){
m_pTcpSocket->connectToHost(hostname,port, QIODevice::ReadWrite);
}
}
Write: 写:
void sendMessage(QString msgToSend){
QByteArray l_vDataToBeSent;
QDataStream l_vStream(&l_vDataToBeSent, QIODevice::WriteOnly);
l_vStream.setByteOrder(QDataStream::LittleEndian);
l_vStream << msgToSend.length();
l_vDataToBeSent.append(msgToSend);
m_pTcpSocket->write(l_vDataToBeSent, l_vDataToBeSent.length());
}
Read: 读:
void readSocketData(){
while(m_pTcpSocket->bytesAvailable()){
QByteArray receivedData = m_pTcpSocket->readAll();
}
}
看看QWebSocket,它基于HTTP,它也允许使用HTTPS
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.