我在C#中使用套接字编程创建了一个简单的服务器,它将从客户端接收文件。我的示例代码段如下所示。
我想添加一些限制。我想限制文件大小(例如4 KB或2 KB)和允许的文件格式(例如.doc,.txt,.cpp等),这些格式将在客户端发送到客户端连接到服务器,以便客户端可以相应地发送文件。我该怎么做?
示例代码段:
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Text;
namespace FileTransfer
{
class Program
{
static void Main(string[] args)
{
// Listen on port 1234
TcpListener tcpListener = new TcpListener(IPAddress.Any, 1234);
tcpListener.Start();
Console.WriteLine("Server started");
//Infinite loop to connect to new clients
while (true)
{
// Accept a TcpClient
TcpClient tcpClient = tcpListener.AcceptTcpClient();
Console.WriteLine("Connected to client");
byte[] data = new byte[1024];
NetworkStream ns = tcpClient.GetStream();
int recv = ns.Read(data, 0, data.Length);
StreamReader reader = new StreamReader(tcpClient.GetStream());
//Will add some lines to add restrictions...
}
}
}
}
我必须在代码中添加哪些附加行才能将限制发送给客户端?
答案 0 :(得分:4)
基本上我认为主要是你需要两件事:
按照其他答案
并处理部分读/写
对于处理部分读取(不确定write
需要多少此类功能),您可以使用below之类的函数:
public static void ReadWholeArray (Stream stream, byte[] data)
{
int offset=0;
int remaining = data.Length;
while (remaining > 0)
{
int read = stream.Read(data, offset, remaining);
if (read <= 0)
throw new EndOfStreamException
(String.Format("End of stream reached with {0} bytes left to read", remaining));
remaining -= read;
offset += read;
}
}
传统Stream.Read()
并不能保证读取尽可能多的字节数,另一方面,这种方法可以确保读取data.Length
中指定的字节数参数。因此,您可以使用此类函数来实现所需的应用程序协议。
您会发现有关此类应用程序协议的一些相关信息here
好的,这是例如服务器如何发送文件长度限制和文件扩展名:
// Send string
string ext = ".txt";
byte [] textBytes = Encoding.ASCII.GetBytes(ext);
ns.Write(textBytes, 0, textBytes.Length);
// Now, send integer - the file length limit parameter
int limit = 333;
byte[] intBytes = BitConverter.GetBytes(limit);
ns.Write(intBytes, 0, intBytes.Length); // send integer - mind the endianness
但你仍然需要某种协议,否则你应该让客户阅读&#34; full&#34;稍后以某种方式流式传输和解析这些数据,如果数据没有固定的长度等,这不是一件小事 - 否则客户端将如何区分消息的哪一部分是文本,哪个整数?
答案 1 :(得分:3)
你似乎正在犯古典套接字错误。给定的代码和解释似乎假设消息中的套接字句柄。 他们不。以这种方式使用时,您使用的是streaming internet sockets,它提供流,而不是消息。
您不会显示任何执行实际发送的代码,因此我猜测您只是将文件的数据泵到另一侧并关闭连接。你怎么知道你已经成功转移了整个文件?
客户端和服务器为了通过套接字有用地交换数据而必须遵循的这组规则称为application protocol。您将必须拥有一个,否则您只是向$ deity发送数据知道在哪里,而您根本无法控制它。这意味着服务器和客户端都会知道发生了什么,他们只是在发送和接收数据,并希望一切顺利。所以没有&#34;几行&#34;你必须添加到你的代码中,你必须完全重组它。
有许多方法可以定义应用程序协议和许多可供选择的选项,因此我将向您展示一个任意方式:对带有ID和有效负载长度前缀的消息的文本说明(如果适用的),都在未指定的数字变量中。例如,您可以选择小端四字节无符号整数。
此格式的邮件称为"Type/Length/Value" or TLV。 所以我们定义这些消息:
ID Name Direction Description Payload
1 ServerHello Server -> Client The server sends this message None.
to every connecting client. Or maybe server or
protocol version.
2 MaxUpload Server -> Client Sent after the ServerHello. Maximum upload size
in bytes.
3 AllowedExts Server -> Client Allowed upload extensions, The allowed extensions.
comma-separated. Sent after
MaxUpload message.
10 IncomingFile Client -> Server There's a file coming. The file name.
11 FileUpload Client -> Server The file to upload. The file data.
Sent after IncomingFile.
现在所需要的只是在服务器和客户端中实现此应用程序协议并且您已完成。
如果客户端或服务器不遵守prototol,您还必须决定该怎么做。例如,它可以发送您无法解析的消息,未知的消息ID,您不想支持的消息长度,无序消息(IncomingFile之前的FileUpload)或消息这并不符合之前发送的消息,例如客户端上传的文件比服务器所说的更大,或者是无效的扩展名。你还必须考虑&#34;确认&#34;或响应消息,如服务器告诉客户端&#34;好的,继续,发送下一条消息&#34;。
总而言之,这是非常广泛的问题,而且不容易回答。我试着在我对您的问题的评论中解决这个问题,该问题已被删除。所以,你有答案。
您可以在网络上详细了解相关信息,例如Beej's Guide to Network Programming与Giorgi相关联(请务必阅读整篇指南)和Stephen Cleary's blog。