將問題拆為「發送資料」與「接收資料」兩部分。程式碼重點在思路而非語法,若從第一篇讀到此應易理解。
class Server {
static void Main(string[] args) {
Console.WriteLine("Server is running ... ");
IPAddress ip = IPAddress.Parse("127.0.0.1");
TcpListener listener = new TcpListener(ip, 8500);
listener.Start(); // 監聽控制埠 8500
Console.WriteLine("Start Listening ...");
while (true) {
TcpClient client = listener.AcceptTcpClient(); // 同步取得控制連線
RemoteClient wrapper = new RemoteClient(client);
wrapper.BeginRead(); // 啟動非同步讀取
}
}
}
public class RemoteClient {
private TcpClient client;
private NetworkStream streamToClient;
private const int BufferSize = 8192;
private byte[] buffer;
private ProtocolHandler handler;
public RemoteClient(TcpClient client) {
this.client = client;
Console.WriteLine("\nClient Connected!{0} <-- {1}",
client.Client.LocalEndPoint, client.Client.RemoteEndPoint);
streamToClient = client.GetStream();
buffer = new byte[BufferSize];
handler = new ProtocolHandler();
}
public void BeginRead() {
AsyncCallback callback = new AsyncCallback(OnReadComplete);
streamToClient.BeginRead(buffer, 0, BufferSize, callback, null);
}
private void OnReadComplete(IAsyncResult ar) {
int bytesRead = 0;
try {
lock (streamToClient) {
bytesRead = streamToClient.EndRead(ar);
Console.WriteLine("\nReading data, {0} bytes ...", bytesRead);
}
if (bytesRead == 0) throw new Exception("讀取到 0 位元組");
string msg = Encoding.Unicode.GetString(buffer, 0, bytesRead);
Array.Clear(buffer, 0, buffer.Length); // 清除髒讀
// 解析協議陣列(處理合併/拆分)
string[] protocolArray = handler.GetProtocol(msg);
foreach (string pro in protocolArray) {
// 非同步分派處理,避免阻塞讀取迴圈
ParameterizedThreadStart start = new ParameterizedThreadStart(handleProtocol);
start.BeginInvoke(pro, null, null);
}
// 重新啟動讀取,形成無限迴圈
lock (streamToClient) {
AsyncCallback callback = new AsyncCallback(OnReadComplete);
streamToClient.BeginRead(buffer, 0, BufferSize, callback, null);
}
} catch (Exception ex) {
if (streamToClient != null) streamToClient.Dispose();
client.Close();
Console.WriteLine(ex.Message);
}
}
private void handleProtocol(object obj) {
string pro = obj as string;
ProtocolHelper helper = new ProtocolHelper(pro);
FileProtocol protocol = helper.GetProtocol();
if (protocol.Mode == FileRequestMode.Send) {
receiveFile(protocol); // 客戶端送檔 → 伺服器收檔
} else if (protocol.Mode == FileRequestMode.Receive) {
// sendFile(protocol); // 待實作
}
}
private void receiveFile(FileProtocol protocol) {
// 取得客戶端 IP,依協議指定埠號連回
IPEndPoint endpoint = client.Client.RemoteEndPoint as IPEndPoint;
IPAddress ip = endpoint.Address;
endpoint = new IPEndPoint(ip, protocol.Port);
TcpClient localClient;
try {
localClient = new TcpClient();
localClient.Connect(endpoint);
} catch {
Console.WriteLine("無法連接到客戶端 --> {0}", endpoint); return;
}
NetworkStream streamToClient = localClient.GetStream();
string path = Environment.CurrentDirectory + "/" + generateFileName(protocol.FileName);
byte[] fileBuffer = new byte[1024];
FileStream fs = new FileStream(path, FileMode.CreateNew, FileAccess.Write);
int bytesRead, totalBytes = 0;
do {
bytesRead = streamToClient.Read(fileBuffer, 0, fileBuffer.Length);
fs.Write(fileBuffer, 0, bytesRead);
totalBytes += bytesRead;
Console.WriteLine("Receiving {0} bytes ...", totalBytes);
} while (bytesRead > 0);
Console.WriteLine("Total {0} bytes received, Done!", totalBytes);
streamToClient.Dispose(); fs.Dispose(); localClient.Close();
}
private string generateFileName(string fileName) {
DateTime now = DateTime.Now;
return String.Format("{0}_{1}_{2}_{3}", now.Minute, now.Second, now.Millisecond, fileName);
}
}