我有一个tcp客户端 - 服务器实现在不同的后台工作线程上运行在同一个程序中。在多台计算机上会有这个程序的实例,因此它们可以在彼此之间发送和接收文件。我可以使用网络流在计算机之间顺序发送文件,但是如何从计算机A到B同时发送多个文件。
通过一个连接(套接字)发送多个文件很好,但是有多个网络流将数据发送到客户端,客户端不知道哪个数据块与哪个文件分开?
客户端是否可以连接两次到服务器(在差异端口上,因为“随机”/未使用的端口被分配给连接)然后每个连接都有自己的流,允许2个文件同时发送?
感谢您的时间和精力。
答案 0 :(得分:5)
客户端当然可以多次连接到服务器 - 可能应该。
您可以指定相同的服务器端口 - 将在服务器端分配不同的本地端口,但客户端不需要知道该端口。 (想想一个Web服务器 - 很多的客户端将同时连接到端口80.)
当然,您也将自动分配单独的客户端端口 - 基本上连接不应相互干扰。
答案 1 :(得分:3)
您需要使用Asyncronous Client和服务器套接字。基本上不使用Recieve和Send,而是使用BeginRecieve,BeginSend,BeginConnect和BeginAccept。这样就可以为您完成线程化。在工作线程中建立每个连接都不是一个好主意。这样,每个新请求都可以同时处理(非同步)。您还可以使用发送文件的前几个字节来存储有关该文件的数据。以下示例。当然,下面的数字(1,2,3 ..)将是一个字符串文件名,你称之为Bitconverter.GetBytes(String var)。希望这可以帮助。 maxpfc@gmail.com(skype)
byte[] completefile = [1,2,3,4,5,6,7,8,9];
byte[] filename;
filename = split(lcomplefile, 3);
以下是Asyc Sockets的可编辑示例。
using System;
using System.Drawing;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Windows.Forms;
class AsyncTcpClient Form:
{
private TextBox newText;
private TextBox conStatus;
private ListBox results;
private Socket client;
private byte[] data = new byte[1024];
private int size = 1024;
public AsyncTcpClient()
{
Text = "Asynchronous TCP Client";
Size = new Size(400, 380);
Label label1 = new Label();
label1.Parent = this;
label1.Text = "Enter text string:";
label1.AutoSize = true;
label1.Location = new Point(10, 30);
newText = new TextBox();
newText.Parent = this;
newText.Size = new Size(200, 2 * Font.Height);
newText.Location = new Point(10, 55);
results = new ListBox();
results.Parent = this;
results.Location = new Point(10, 85);
results.Size = new Size(360, 18 * Font.Height);
Label label2 = new Label();
label2.Parent = this;
label2.Text = "Connection Status:";
label2.AutoSize = true;
label2.Location = new Point(10, 330);
conStatus = new TextBox();
conStatus.Parent = this;
conStatus.Text = "Disconnected";
conStatus.Size = new Size(200, 2 * Font.Height);
conStatus.Location = new Point(110, 325);
This document is created with the unregistered version of CHM2PDF Pilot
Button sendit = new Button();
sendit.Parent = this;
sendit.Text = "Send";
sendit.Location = new Point(220,52);
sendit.Size = new Size(5 * Font.Height, 2 * Font.Height);
sendit.Click += new EventHandler(ButtonSendOnClick);
Button connect = new Button();
connect.Parent = this;
connect.Text = "Connect";
connect.Location = new Point(295, 20);
connect.Size = new Size(6 * Font.Height, 2 * Font.Height);
connect.Click += new EventHandler(ButtonConnectOnClick);
Button discon = new Button();
discon.Parent = this;
discon.Text = "Disconnect";
discon.Location = new Point(295,52);
discon.Size = new Size(6 * Font.Height, 2 * Font.Height);
discon.Click += new EventHandler(ButtonDisconOnClick);
}
void ButtonConnectOnClick(object obj, EventArgs ea)
{
conStatus.Text = "Connecting...";
Socket newsock = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
IPEndPoint iep = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 9050);
newsock.BeginConnect(iep, new AsyncCallback(Connected), newsock);
}
void ButtonSendOnClick(object obj, EventArgs ea)
{
byte[] message = Encoding.ASCII.GetBytes(newText.Text);
newText.Clear();
client.BeginSend(message, 0, message.Length, SocketFlags.None,
new AsyncCallback(SendData), client);
}
void ButtonDisconOnClick(object obj, EventArgs ea)
{
client.Close();
conStatus.Text = "Disconnected";
}
void Connected(IAsyncResult iar)
{
client = (Socket)iar.AsyncState;
try
{
client.EndConnect(iar);
conStatus.Text = "Connected to: " + client.RemoteEndPoint.ToString();
client.BeginReceive(data, 0, size, SocketFlags.None,
new AsyncCallback(ReceiveData), client);
} catch (SocketException)
{
conStatus.Text = "Error connecting";
}
}
void ReceiveData(IAsyncResult iar)
{
Socket remote = (Socket)iar.AsyncState;
int recv = remote.EndReceive(iar);
string stringData = Encoding.ASCII.GetString(data, 0, recv);
results.Items.Add(stringData);
}
void SendData(IAsyncResult iar)
{
Socket remote = (Socket)iar.AsyncState;
int sent = remote.EndSend(iar);
remote.BeginReceive(data, 0, size, SocketFlags.None,
This document is created with the unregistered version of CHM2PDF Pilot
new AsyncCallback(ReceiveData), remote);
}
public static void Main()
{
Application.Run(new AsyncTcpClient());
}
}
答案 2 :(得分:1)
客户端是否可以连接两次到服务器(在差异端口上,因为“随机”/未使用的端口被分配给连接)然后每个连接都有自己的流,允许2个文件同时发送?
是;这就是网络协议通常的工作方式。您无需在服务器端选择新的端口号:即使您侦听固定的端口号,与该端口的连接也是分开的。
例如,www.stackoverflow.com上的Web服务器总是侦听端口80,但是您和我可以从我们的Web浏览器进行连接,并且我们的连接不会混淆。
答案 3 :(得分:1)
你可以这样做,但我没有看到好处。除非每个连接都被限制在某个地方,否则你实际上会产生两倍于I / O操作的开销。
这与将文件写入磁盘相同,只是因为将其拆分为两个线程并不意味着它会更快,因为磁盘只能一次写入。实际上,您可能会看到较慢的响应时间。
答案 4 :(得分:0)
您必须在单个套接字上添加协议以识别哪些数据是哪个文件的一部分,或者使用多个套接字以便您知道每个文件的开始和结束位置。
即使有多个套接字,如果要在没有套接字打开/关闭内务处理的情况下重新使用相同的套接字,也必须有开始/结束标记。
为什么不能使用FTP?