- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
如果其中一些问题对于专业网络程序员来说很明显,我先向您道歉。我已经研究并阅读了有关网络编码的信息,但我仍然不清楚如何做到这一点。
假设我想编写一个TCP代理(进行中),其中包含一些TCP客户端和某些TCP服务器之间的连接。像这样的东西:
首先,假设这些连接是半永久性的(很长一段时间后将关闭),我需要按顺序到达数据。
我要实现的想法如下:每当我从客户端收到请求时,我都希望将该请求转发到后端服务器,然后等待(不执行任何操作),直到后端服务器响应我(代理),然后将响应转发给客户端(假定在通常情况下两个TCP连接都将保持不变)。
有一个主要问题,我不确定如何解决。当我将请求从代理转发到服务器并获得响应时,如果我事先不知道从服务器发送到的数据格式,我如何知道服务器何时向我发送了我需要的所有信息。代理(即,我不知道来自服务器的响应是否为type-length-value scheme形式,也不知道`\r\n\是否表示来自服务器的消息结尾)。有人告诉我应该假设,只要我从tcp连接读取的大小为零或小于预期的读取大小,就将从服务器连接中获取所有数据。但是,这对我来说似乎不正确。通常,它可能不正确的原因如下:
假设由于某种原因,服务器一次只向其套接字写入一个字节,但是对“真实”客户端的响应的总长度要长得多。因此,当代理读取连接到服务器的tcp套接字时,代理是否仅读取一个字节,并且如果其循环足够快(在接收更多数据之前进行读取),然后零读取且错误地读取,这是不可能的。得出的结论是,它已收到客户端打算接收的所有消息?
解决此问题的一种方法可能是在每次从套接字读取后等待,以使代理不会比获取字节更快地循环。我担心的原因是,假设有一个网络分区,我再也无法与服务器通信了。但是,它与我的连接断开的时间还不够长,无法使TCP连接超时。因此,是否有可能我尝试再次从tcp套接字读取到服务器(比获取数据快)并读取零并错误地得出结论,即所有数据然后将其打包发送给客户端? (请记住,我要保留的 promise 是,我仅在写入客户端连接时才将整个消息发送给客户端。因此,如果代理出现故障,则考虑正确的行为是非法的,在此之后的稍后时间再次读取该连接已写入客户端,并在以后的某个时间(可能在其他请求的响应期间)发送丢失的数据块)。
我写的代码在go-playground.中
我喜欢用来解释为什么我认为这种方法不起作用的类比如下:
假设我们有一个杯子,代理每次从服务器读取内容时,代理服务器就会喝掉一半的杯子,但是服务器一次只能放入1茶匙。因此,如果代理喝得快于得到茶匙,它可能会太早达到零,并得出结论说它的 socket 是空的,可以继续前进了!如果我们要保证每次都发送完整的消息,那是错误的。要么,这种类比是错误的,并且TCP的某些“魔术”使其起作用,或者假定直到套接字为空的算法是完全错误的。
此处处理类似问题的question建议阅读直到EOF
为止。但是,我不确定为什么这是正确的。阅读EOF
是否意味着我收到了缩进的消息?每当有人向tcp套接字写入大块字节时是否发送EOF
(即,我担心如果服务器一次写入一个字节,则每字节发送1个EOF
)吗?但是,EOF
可能是TCP连接实际工作方式的“魔术”?发送EOF
是否关闭连接?如果它不是我要使用的方法。另外,我无法控制服务器的工作方式(即,我不知道它要多久写入一次套接字以将数据发送到代理,但是可以合理地假设它以某种“标准”写入套接字/socket的正常写入算法”)。我只是不相信从服务器的套接字读取直到EOF
是正确的。为什么会这样呢?我什么时候甚至可以阅读EOF
? EOF
是数据的一部分还是它们在TCP报头中?
另外,我写的关于将等待放在epsilon超时以下的想法,在最坏的情况下还是只能在平均情况下起作用?我也在想,我意识到,如果Wait()调用的时间长于超时时间,那么如果您返回到tcp连接并且它没有任何内容,则可以继续进行。但是,如果它什么都没有并且我们不知道服务器发生了什么,那么我们将超时。因此可以安全地关闭连接(因为超时无论如何都会这样做)。因此,我认为如果Wait调用至少与超时时间一样长,则此过程确实有效!人们怎么看?
我也对一个可以证明为什么这种算法在某些情况下可行的答案很感兴趣。例如,我在想,即使服务器一次只写一个字节,如果部署的环境是一个紧凑的数据中心,那么平均而言,因为延迟非常小并且等待调用几乎可以肯定就够了,这种算法不好吗?
此外,我编写的代码陷入“僵局”是否有任何风险?
package main
import (
"fmt"
"net"
)
type Proxy struct {
ServerConnection *net.TCPConn
ClientConnection *net.TCPConn
}
func (p *Proxy) Proxy() {
fmt.Println("Running proxy...")
for {
request := p.receiveRequestClient()
p.sendClientRequestToServer(request)
response := p.receiveResponseFromServer() //<--worried about this one.
p.sendServerResponseToClient(response)
}
}
func (p *Proxy) receiveRequestClient() (request []byte) {
//assume this function is a black box and that it works.
//maybe we know that the messages from the client always end in \r\n or they
//they are length prefixed.
return
}
func (p *Proxy) sendClientRequestToServer(request []byte) {
//do
bytesSent := 0
bytesToSend := len(request)
for bytesSent < bytesToSend {
n, _ := p.ServerConnection.Write(request)
bytesSent += n
}
return
}
// Intended behaviour: waits until ALL of the response from backend server is obtained.
// What it does though, assumes that if it reads zero, that the server has not yet
// written to the proxy and therefore waits. However, once the first byte has been read,
// keeps writting until it extracts all the data from the server and the socket is "empty".
// (Signaled by reading zero from the second loop)
func (p *Proxy) receiveResponseFromServer() (response []byte) {
bytesRead, _ := p.ServerConnection.Read(response)
for bytesRead == 0 {
bytesRead, _ = p.ServerConnection.Read(response)
}
for bytesRead != 0 {
n, _ := p.ServerConnection.Read(response)
bytesRead += n
//Wait(n) could solve it here?
}
return
}
func (p *Proxy) sendServerResponseToClient(response []byte) {
bytesSent := 0
bytesToSend := len(request)
for bytesSent < bytesToSend {
n, _ := p.ServerConnection.Write(request)
bytesSent += n
}
return
}
func main() {
proxy := &Proxy{}
proxy.Proxy()
}
最佳答案
除非您使用特定的更高级别的协议(protocol),否则没有从客户端读取以中继到服务器的“消息”。 TCP是一种流协议(protocol),您所能做的就是来回穿梭字节。
好消息是,这样做非常容易,此代理的核心部分将是:
go io.Copy(server, client)
io.Copy(client, server)
关于sockets - 如何使用TCP连接在Go(golang)中编写代理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25090690/
我知道这个问题可能已经被问过,但我检查了所有这些,我认为我的情况有所不同(请友善)。所以我有两个数据集,第一个是测试数据集,第二个是我保存在数据框中的预测(预测值,这就是没有数据列的原因)。我想合并两
在 .loc 方法的帮助下,我根据同一数据框中另一列中的值来识别 Panda 数据框中某一列中的值。 下面给出了代码片段供您引用: var1 = output_df['Player'].loc[out
当我在 Windows 中使用 WinSCP 通过 Ubuntu 连接到 VMware 时,它提示: The server rejected SFTP connection, but it lis
我正在开发一个使用 xml web 服务的 android 应用程序。在 wi-fi 网络中连接时工作正常,但在 3G 网络中连接时失败(未找到 http 404)。 这不仅仅发生在设备中。为了进行测
我有一个XIB包含我的控件的文件,加载到 Interface Builder(Snow Leopard 上的 Xcode 4.0.2)中。 文件的所有者被设置为 someClassController
我在本地计算机上管理 MySQL 数据库,并通过运行以下程序通过 C 连接到它: #include #include #include int main(int argc, char** arg
我不知道为什么每次有人访问我网站上的页面时,都会打开一个与数据库的新连接。最终我到达了大约 300 并收到错误并且页面不再加载。我认为它应该工作的方式是,我将 maxIdle 设置为 30,这意味着
希望清理 NMEA GPS 中的 .txt 文件。我当前的代码如下。 deletes = ['$GPGGA', '$GPGSA', '$GPGSV', '$PSRF156', ] searchquer
我有一个 URL、一个用户名和一个密码。我想在 C# .Net WinForms 中建立 VPN 连接。 你能告诉我从哪里开始吗?任何第三方 API? 代码示例将受到高度赞赏... 最佳答案 您可以像
有没有更好的方法将字符串 vector 转换为字符 vector ,字符串之间的终止符为零。 因此,如果我有一个包含以下字符串的 vector "test","my","string",那么我想接收一
我正在编写一个库,它不断检查 android 设备的连接,并在设备连接、断开连接或互联网连接变慢时给出回调。 https://github.com/muddassir235/connection_ch
我的操作系统:Centos 7 + CLOUDLINUX 7.7当我尝试从服务器登录Mysql时 [root@server3 ~]# Mysql -u root -h localhost -P 330
我收到错误:Puma 发现此错误:无法打开到本地主机的 TCP 连接:9200(连接被拒绝 - 连接(2)用于“本地主机”端口 9200)(Faraday::ConnectionFailed)在我的
请给我一些解决以下错误的方法。 这是一个聊天应用....代码和错误如下:: conversations_controller.rb def create if Conversation.bet
我想将两个单元格中的数据连接到一个单元格中。我还想只组合那些具有相同 ID 的单元格。 任务 ID 名称 4355.2 参与者 4355.2 领袖 4462.1 在线 4462.1 快速 4597.1
我经常需要连接 TSQL 中的字段... 使用“+”运算符时 TSQL 强制您处理的两个问题是 Data Type Precedence和 NULL 值。 使用数据类型优先级,问题是转换错误。 1)
有没有在 iPad 或 iPhone 应用程序中使用 Facebook 连接。 这个想法是登录这个应用程序,然后能够看到我的哪些 facebook 用户也在使用该应用程序及其功能。 最佳答案 是的。
我在连接或打印字符串时遇到了一个奇怪的问题。我有一个 char * ,可以将其设置为字符串文字的几个值之一。 char *myStrLiteral = NULL; ... if(blah) myS
对于以下数据 - let $x := "Yahooooo !!!! Select one number - " let $y := 1 2 3 4 5 6 7 我想得到
我正在看 UDEMY for perl 的培训视频,但是视频不清晰,看起来有错误。 培训展示了如何使用以下示例连接 2 个字符串: #!usr/bin/perl print $str = "Hi";
我是一名优秀的程序员,十分优秀!