這裡應該沒有什麼新知識,需要注意的地方有這麼幾個:
在OnReadComplete()回調方法中的foreach循環,我們使用委托異步調用了handleProtocol()方法,這 是因為handleProtocol即將執行的是一個讀取或接收文件的操作,也就是一個相對耗時的操作。
在handleProtocol()方法中,我們深切體會了定義ProtocolHelper類和FileProtocol結構的好處。如 果沒有定義它們,這裡將是不堪入目的處理XML以及類型轉換的代碼。
handleProtocol()方法中進行了一個條件判斷,注意sendFile()方法我屏蔽掉了,這個還沒有實現, 但是我想你已經猜到它將是後面要實現的內容。
receiveFile()方法是實際接收客戶端發來文件的方法,這裡沒有什麼特別之處。需要注意的是文件存 儲的路徑,它保存在了當前程序執行的目錄下,文件的名稱我使用generateFileName()生成了一個與時間 有關的隨機名稱。
3.2客戶端的實現
我們現在先不著急實現客戶端S1、R1等用戶菜單,首先完成發送文件這一功能,實際上,就是為上一 節SendMessage()加一個姐妹方法SendFile()。
class ClIEnt {
static void
Main(string[] args) {
ConsoleKey key;
ServerClient client = new ServerClIEnt();
string filePath = Environment.CurrentDirectory + "/" + "ClIEnt01.jpg";
if(File.Exists(filePath))
clIEnt.BeginSendFile(filePath);
Console.WriteLine("\n\n輸入\"Q\"鍵退出。");
do {
key = Console.ReadKey(true).Key;
} while (key != ConsoleKey.Q);
}
}
public class ServerClIEnt {
private const int BufferSize = 8192;
private byte[] buffer;
private TcpClient clIEnt;
private NetworkStream streamToServer;
public ServerClIEnt() {
try {
client = new TcpClIEnt();
clIEnt.Connect("localhost", 8500); // 與服務器連接
} catch (Exception ex) {
Console.WriteLine(ex.Message);
return;
}
buffer = new byte[BufferSize];
// 打印連接到的服務端信息
Console.WriteLine("Server Connected!{0} --> {1}",
client.Client.LocalEndPoint, client.ClIEnt.RemoteEndPoint);
streamToServer = clIEnt.GetStream();
}
// 發送消息到服務端
public void SendMessage(string msg) {
byte[] temp = Encoding.Unicode.GetBytes(msg); // 獲得緩存
try {
lock (streamToServer) {
streamToServer.Write(temp, 0, temp.Length); // 發往服務器
}
Console.WriteLine("Sent: {0}", msg);
} catch (Exception ex) {
Console.WriteLine(ex.Message);
return;
}
}
// 發送文件 - 異步方法
public void BeginSendFile(string filePath) {
ParameterizedThreadStart start =
new ParameterizedThreadStart(BeginSendFile);
start.BeginInvoke(filePath, null, null);
}
private void BeginSendFile(object obj) {
string filePath = obj as string;
SendFile(filePath);
}
// 發送文件 -- 同步方法
public void SendFile(string filePath) {
IPAddress ip = IPAddress.Parse("127.0.0.1");
TcpListener listener = new TcpListener(ip, 0);
listener.Start();
// 獲取本地偵聽的端口號
IPEndPoint endPoint = listener.LocalEndpoint as IPEndPoint;
int listeningPort = endPoint.Port;
// 獲取發送的協議字符串
string fileName = Path.GetFileName(filePath);
FileProtocol protocol =
new FileProtocol(FileRequestMode.Send, listeningPort, fileName);
string pro = protocol.ToString();
SendMessage(pro); // 發送協議到服務端
// 中斷,等待遠程連接
TcpClient localClient = listener.AcceptTcpClIEnt();
Console.WriteLine("Start sending file...");
NetworkStream stream = localClIEnt.GetStream();
// 創建文件流
FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read);
byte[] fileBuffer = new byte[1024]; // 每次傳1KB
int bytesRead;
int totalBytes = 0;
// 創建獲取文件發送狀態的類
SendStatus status = new SendStatus(filePath);
// 將文件流轉寫入網絡流
try {
do {
Thread.Sleep(10); // 為了更好的視覺效果 ,暫停10毫秒:-)
bytesRead = fs.Read(fileBuffer, 0, fileBuffer.Length);
stream.Write(fileBuffer, 0, bytesRead);
totalBytes += bytesRead; // 發送了的 字節數
status.PrintStatus(totalBytes); // 打印發送狀態
} while (bytesRead > 0);
Console.WriteLine("Total {0} bytes sent, Done!", totalBytes);
} catch {
Console.WriteLine("Server has lost...");
}
stream.Dispose();
fs.Dispose();
localClIEnt.Close();
listener.Stop();
}
}