我有一个服务器,其中有几个IP地址分配给网络适配器.
在该服务器上是一个客户端应用程序,通过TCPClient连接到另一个服务器应用程序.对于所有传出通信,我的服务器使用默认IP地址,但是对于这一个应用程序,我希望将传出通信发送到另一个本地IP地址.
是否可以在通信时指定另一个本地分配的IP?
我正在尝试使远程服务器应用程序认为它来自另一个IP,因此它将通过防火墙等....
提前致谢
据我了解,TcpListener一旦你打电话就会排队连接Start().每次调用AcceptTcpClient(或BeginAcceptTcpClient)时,它都会从队列中出列一个项目.
如果我们TcpListener通过立即向它发送1,000个连接来加载测试我们的应用程序,那么队列构建的速度远远超过我们清除它的速度,导致(最终)从客户端超时,因为它没有得到响应,因为它的连接仍在队列.但是,服务器似乎没有太大的压力,我们的应用程序不会消耗太多CPU时间,并且机器上的其他受监控资源也不会让人痛苦.感觉就像我们现在没有足够高效地运行.
我们正在调用BeginAcceptTcpListener然后立即移交给一个ThreadPool线程来实际完成工作,然后BeginAcceptTcpClient再次调用.所涉及的工作似乎没有对机器施加任何压力,它基本上只是一个3秒的睡眠,然后是字典查找,然后是100字节写入TcpClient流.
这是TcpListener我们使用的代码:
// Thread signal.
private static ManualResetEvent tcpClientConnected = new ManualResetEvent(false);
public void DoBeginAcceptTcpClient(TcpListener listener)
{
// Set the event to nonsignaled state.
tcpClientConnected.Reset();
listener.BeginAcceptTcpClient(
new AsyncCallback(DoAcceptTcpClientCallback),
listener);
// Wait for signal
tcpClientConnected.WaitOne();
}
public void DoAcceptTcpClientCallback(IAsyncResult ar)
{
// Get the listener that handles the client request, and the TcpClient
TcpListener listener = (TcpListener)ar.AsyncState;
TcpClient client …Run Code Online (Sandbox Code Playgroud) 我正在用C#编写客户端/服务器应用程序,而且它很棒.现在,一切正常,而且非常强大.我的问题是,当通过连接发送数据包时,我遇到了一些延迟.
在客户端我这样做:
NetworkStream ns = tcpClient.GetStream();
// Send packet
byte[] sizePacket = BitConverter.GetBytes(request.Length);
byte[] requestWithHeader = new byte[sizePacket.Length + request.Length];
sizePacket.CopyTo(requestWithHeader, 0);
request.CopyTo(requestWithHeader, sizePacket.Length);
ns.Write(requestWithHeader, 0, requestWithHeader.Length);
// Receive response
ns.Read(sizePacket, 0, sizePacket.Length);
int responseLength = BitConverter.ToInt32(sizePacket, 0);
byte[] response = new byte[responseLength];
int bytesReceived = 0;
while (bytesReceived < responseLength)
{
int bytesRead = ns.Read(response, bytesReceived, responseLength - bytesReceived);
bytesReceived += bytesRead;
}
Run Code Online (Sandbox Code Playgroud)
(遗漏了一些异常捕获等)服务器执行相反的操作,即它在NetworkStream.Read()上阻塞,直到它有一个完整的请求,然后处理它并使用Write()发送响应.
Write()/ Read()的原始速度不是问题(即发送大数据包很快),但是在不关闭连接的情况下一个接一个地发送几个小数据包可能非常慢(延迟50-100)女士).奇怪的是,这些延迟出现在LAN连接上,典型的ping时间<1 ms,但如果服务器在localhost上运行则不会发生,即使ping时间实际上是相同的(至少差异不应该是大约100毫秒).如果我在每个数据包上重新打开连接,导致大量握手,那对我来说是有意义的,但我不是.这就好像服务器进入等待状态会使它与客户端失去同步,然后在重新建立本质上是丢失的连接时发现它有点绊倒.
那么,我做错了吗?有没有办法保持TcpServer和TcpClient之间的连接同步,以便服务器随时准备接收数据?(反之亦然:有时处理来自客户端的请求需要几毫秒,然后客户端似乎没有准备好接收来自服务器的响应,直到它在Read()上阻塞之后有一些时刻被唤醒.)
我试图将一个古老的网络摄像头连接到我的计算机,我陷入了一个非常根本的问题 - 检测流的结束.
我正在使用TcpClient与相机通信,我实际上可以看到它传输命令数据,这里没有问题.
List<int> incoming = new List<int>();
TcpClient clientSocket = new TcpClient();
clientSocket.Connect(txtHost.Text, Int32.Parse(txtPort.Text));
NetworkStream serverStream = clientSocket.GetStream();
serverStream.Flush();
byte[] command = System.Text.Encoding.ASCII.GetBytes("i640*480M");
serverStream.Write(command, 0, command.Length);
Run Code Online (Sandbox Code Playgroud)
回读响应是问题的开始.我最初认为像下面的一些代码一样简单:
while (serverStream.DataAvailable)
{
incoming.Add(serverStream.ReadByte());
}
Run Code Online (Sandbox Code Playgroud)
但它没有,所以这次使用ReadByte()进行了另一个版本.描述说明:
从流中读取一个字节并将流中的位置前进一个字节,如果在流的末尾则返回-1.
所以我想我可以实现以下几点:
Boolean run = true;
int rec;
while (run)
{
rec = serverStream.ReadByte();
if (rec == -1)
{
run = false;
//b = (byte)'X';
}
else
{
incoming.Add(rec);
}
}
Run Code Online (Sandbox Code Playgroud)
不,仍然无法正常工作.我实际上可以看到数据进入和某个点之后(这并不总是相同的,否则我每次只能读取那么多字节)我开始得到0其余元素的值并且它不会停止直到我手动停止执行.这是它的样子:

所以我的问题是,我错过了一些基本的东西吗?如何检测流的结束?
非常感谢,
H.
根据@ Len-Holgate 在这个问题中的建议,我异步请求0字节读取,并且在回调中,接受字节可用字节和同步读取,因为我知道数据是可用的并且不会阻塞.这看起来非常有效和精彩.
但后来我为SslStream添加了选项,并且方法崩溃了.零字节读取很好,但是SslStream解密字节,在TcpClient的缓冲区中保留零字节计数(恰当如此),我无法确定SslStream中现在有多少字节可用于读取.
有一个简单的伎俩吗?
一些代码,仅用于上下文:
sslStream.BeginRead(this.zeroByteBuffer, 0, 0, DataAvailable, this);
Run Code Online (Sandbox Code Playgroud)
在EndRead()(正确返回0)之后,DataAvailable包含:
// by now this is 0, because sslStream has already consumed the bytes
available = myTcpClient.Available;
if (0 < available) // Never occurs
{
// this part can be distractingly complicated, but
// it's based on the available byte count
sslStream.Read(...);
}
Run Code Online (Sandbox Code Playgroud)
由于协议,我需要逐字节评估和解码可变字节宽度的unicode和东西.我不想异步读取逐字节!
我试图了解NetworkStream.EndRead()的MSDN示例.有些部分我不明白.
所以这是示例(从MSDN复制):
// Example of EndRead, DataAvailable and BeginRead.
public static void myReadCallBack(IAsyncResult ar ){
NetworkStream myNetworkStream = (NetworkStream)ar.AsyncState;
byte[] myReadBuffer = new byte[1024];
String myCompleteMessage = "";
int numberOfBytesRead;
numberOfBytesRead = myNetworkStream.EndRead(ar);
myCompleteMessage =
String.Concat(myCompleteMessage, Encoding.ASCII.GetString(myReadBuffer, 0, numberOfBytesRead));
// message received may be larger than buffer size so loop through until you have it all.
while(myNetworkStream.DataAvailable){
myNetworkStream.BeginRead(myReadBuffer, 0, myReadBuffer.Length,
new AsyncCallback(NetworkStream_ASync_Send_Receive.myReadCallBack),
myNetworkStream);
}
// Print out the received message to the console.
Console.WriteLine("You received the following message …Run Code Online (Sandbox Code Playgroud) 我正在使用TCPListener构建一个Mock服务器.
当我尝试通过运行客户端来调试我的代码时,我能够在服务器上读取请求.但在客户端,正在抛出异常.以下是我从跟踪中获得的异常:
System.ServiceModel.CommunicationException:套接字连接已中止.这可能是由于处理消息的错误或远程主机超出接收超时或基础网络资源问题引起的.本地套接字超时为'00:05:00'.---> System.IO.IOException:无法从传输连接读取数据:已建立的连接已被主机中的软件中止.---> System.Net.Sockets.SocketException:已建立的连接已被主机中的软件中止
这是我在服务器上实现的代码:
TcpClient client = listener.AcceptTcpClient();
NetworkStream nwStream = client.GetStream();
byte[] buffer = new byte[client.ReceiveBufferSize];
int bytesRead = nwStream.Read(buffer, 0, client.ReceiveBufferSize);
var dataReceived = Encoding.ASCII.GetString(buffer, 0, bytesRead);
byte[] sendBytes = null;
try
{
var output = "POST HTTP/1.1 200 OK\r\n";
output += "Server: Apache-Coyote/1.1\r\n";
output += "Content-Type: application/soap+xml\r\n";
output += "Content-Length: 632\r\n";
output += "Date: Thu, 06 Aug 2015 02:06:39 GMT\r\n\r\n";
output +=
"<S:Envelope xmlns:S=\"http://www.w3.org/2003/05/soap-envelope\"><S:Header></S:Header><S:Body></S:Body></S:Envelope>";
sendBytes = Encoding.ASCII.GetBytes(output);
nwStream.Write(sendBytes, 0, sendBytes.Length);
nwStream.Flush();
}
catch (SocketException se) …Run Code Online (Sandbox Code Playgroud) 任何人都能指出这段代码中的缺陷吗?我正在使用TcpClient检索一些HTML.与IIS服务器通信时,NetworkStream.Read()似乎永远不会完成.如果我去使用Fiddler代理,它可以正常工作,但直接与目标服务器通信时,.read()循环将不会退出,直到连接异常时出现"远程服务器已关闭连接"之类的错误.
internal TcpClient Client { get; set; }
/// bunch of other code here...
try
{
NetworkStream ns = Client.GetStream();
StreamWriter sw = new StreamWriter(ns);
sw.Write(request);
sw.Flush();
byte[] buffer = new byte[1024];
int read=0;
try
{
while ((read = ns.Read(buffer, 0, buffer.Length)) > 0)
{
response.AppendFormat("{0}", Encoding.ASCII.GetString(buffer, 0, read));
}
}
catch //(SocketException se)
{
}
finally
{
Close();
}
Run Code Online (Sandbox Code Playgroud)
更新
在调试器中,我可以看到整个响应立即通过并附加到我的StringBuilder(响应).当服务器完成发送响应或我的代码没有检测到它时,似乎连接没有被关闭.
结论 正如这里所说的,最好利用协议的产品(在HTTP的情况下,Content-Length头)来确定事务何时完成.但是,我发现并非所有页面都设置了内容长度.所以,我现在正在使用混合解决方案:
对于所有事务,请将请求的Connection标头设置为"关闭",以防止服务器保持套接字打开.这可以提高服务器在响应您的请求时关闭连接的几率.
如果Content-Length已设置,请使用它来确定请求何时完成.
否则,将NetworkStream的RequestTimeout属性设置为一个大但合理的值,如1秒.然后,循环开启,NetworkStream.Read()直到a)超时发生,或b)您读取的字节数比您要求的少.
感谢大家的出色和详细的回复.
将NetworkStream.Write只阻塞,直到它把要发送到TCP发送缓冲区中的数据,还是会阻塞,直到数据实际上是由接收主机ACK'd?
注意:套接字配置为阻止I/O.
编辑:哎呀,TcpClient.Write当然没有这样的事情!我们都明白我们在谈论TcpClient.GetStream().Write,实际上NetworkStream.Write!
我既有TCP服务器又有一个客户端,简单TCP服务器将仅接收传入的数据并进行打印,并且客户端将不断创建套接字连接并将数据循环发送到TCP服务器。
我得到的信息是,如果正确关闭了TCP连接,则此过程应继续进行而不会发生任何崩溃。
但是从客户端到服务器接收到一定数量的数据后,客户端崩溃并报错
total times data send: 16373
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x10d7594]
goroutine 1 [running]:
main.sendData()
/Users/apple/Desktop/Personal/umbrellaserver/src/tests/clinet.go:178
+0xb4
main.main()
/Users/apple/Desktop/Personal/umbrellaserver/src/tests/clinet.go:170
+0x2a
exit status 2
Run Code Online (Sandbox Code Playgroud)
Server.go
package main
import (
"bufio"
"fmt"
"net"
"sync"
)
var wg sync.WaitGroup
var count = 0
var timeX string = ""
var connQueue = make(chan string)
func main() {
tcpListner := startTCPConnection()
incomingTCPListener(tcpListner)
}
//startTCPConnection
func startTCPConnection() net.Listener {
tcpListner, tcpConnectonError := …Run Code Online (Sandbox Code Playgroud) tcpclient ×10
c# ×9
sockets ×5
tcplistener ×3
.net ×2
asynchronous ×2
asp.net ×1
go ×1
ip-address ×1
sslstream ×1
tcp ×1
tcpserver ×1