版權(quán)說(shuō)明:本文檔由用戶(hù)提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
1、C#網(wǎng)絡(luò)編程(訂立協(xié)議和發(fā)送文件) - Part.4文件傳輸前面兩篇文章所使用的范例都是傳輸字符串,有的時(shí)候我們可能會(huì)想在服務(wù)端和客戶(hù)端之間傳遞文件。比如,考慮這樣一種情況,假如客戶(hù)端顯示了一個(gè)菜單,當(dāng)我們輸入S1、S2或S3(S為Send縮寫(xiě))時(shí),分別向服務(wù)端發(fā)送文件Client01.jpg、Client02.jpg、Client03.jpg;當(dāng)我們輸入R1、R2或R3時(shí)(R為Receive縮寫(xiě)),則分別從服務(wù)端接收文件Server01.jpg、Server02.jpg、Server03.jpg。那么,我們?cè)撊绾瓮瓿蛇@件事呢?此時(shí)可能有這樣兩種做法:· 類(lèi)似于FTP協(xié)議,服務(wù)端開(kāi)辟
2、兩個(gè)端口,并持續(xù)對(duì)這兩個(gè)端口偵聽(tīng):一個(gè)用于接收字符串,類(lèi)似于FTP的控制端口,它接收各種命令(接收或發(fā)送文件);一個(gè)用于傳輸數(shù)據(jù),也就是發(fā)送和接收文件。 · 服務(wù)端只開(kāi)辟一個(gè)端口,用于接收字符串,我們稱(chēng)之為控制端口。當(dāng)接到請(qǐng)求之后,根據(jù)請(qǐng)求內(nèi)容在客戶(hù)端開(kāi)辟一個(gè)端口專(zhuān)用于文件傳輸,并在傳輸結(jié)束后關(guān)閉端口。 現(xiàn)在我們只關(guān)注于上面的數(shù)據(jù)端口,回憶一下在第二篇中我們所總結(jié)的,可以得出:當(dāng)我們使用上面的方法一時(shí),服務(wù)端的數(shù)據(jù)端口可以為多個(gè)客戶(hù)端的多次請(qǐng)求服務(wù);當(dāng)我們使用方法二時(shí),服務(wù)端只為一個(gè)客戶(hù)端的一次請(qǐng)求服務(wù),但是因?yàn)槊看握?qǐng)求都會(huì)重新開(kāi)辟端口,所以實(shí)際上還是相當(dāng)于可以為多個(gè)客戶(hù)端的多次請(qǐng)求
3、服務(wù)。同時(shí),因?yàn)樗粸橐淮握?qǐng)求服務(wù),所以我們?cè)跀?shù)據(jù)端口上傳輸文件時(shí)無(wú)需采用異步傳輸方式。但在控制端口我們?nèi)匀恍枰褂卯惒椒绞健纳厦婵闯?,第一種方式要好得多,但是我們將采用第二種方式。至于原因,你可以回顧一下Part.1(基本概念和操作)中關(guān)于聊天程序模式的講述,因?yàn)榻酉聛?lái)一篇文章我們將創(chuàng)建一個(gè)聊天程序,而這個(gè)聊天程序采用第三種模式,所以本文的練習(xí)實(shí)際是對(duì)下一篇的一個(gè)鋪墊。1 / 361.訂立協(xié)議1.1發(fā)送文件我們先看一下發(fā)送文件的情況,如果我們想將文件client01.jpg由客戶(hù)端發(fā)往客戶(hù)端,那么流程是什么:1. 客戶(hù)端開(kāi)辟數(shù)據(jù)端口用于偵聽(tīng),并獲取端口號(hào),假設(shè)為8005。 2. 假設(shè)客戶(hù)端
4、輸入了S1,則發(fā)送下面的控制字符串到服務(wù)端:file=Client01.jpg, mode=send, port=8005。 3. 服務(wù)端收到以后,根據(jù)客戶(hù)端ip和端口號(hào)與該客戶(hù)端建立連接。 4. 客戶(hù)端偵聽(tīng)到服務(wù)端的連接,開(kāi)始發(fā)送文件。 5. 傳送完畢后客戶(hù)端、服務(wù)端分別關(guān)閉連接。 此時(shí),我們訂立的發(fā)送文件協(xié)議為:file=Client01.jpg, mode=send, port=8005。但是,由于它是一個(gè)普通的字符串,在上一篇中,我們采用了正則表達(dá)式來(lái)獲取其中的有效值,但這顯然不是一種好辦法。因此,在本文及下一篇文章中,我們采用一種新的方式來(lái)編寫(xiě)協(xié)議:XML。對(duì)于上面的語(yǔ)句,我們可以寫(xiě)
5、成這樣的XML:<protocol><file name="client01.jpg" mode="send" port="8005" /></protocol>這樣我們?cè)诜?wù)端就會(huì)好處理得多,接下來(lái)我們來(lái)看一下接收文件的流程及其協(xié)議。NOTE:這里說(shuō)發(fā)送、接收文件是站在客戶(hù)端的立場(chǎng)說(shuō)的,當(dāng)客戶(hù)端發(fā)送文件時(shí),對(duì)于服務(wù)器來(lái)收,則是接收文件。1.2接收文件接收文件與發(fā)送文件實(shí)際上完全類(lèi)似,區(qū)別只是由客戶(hù)端向網(wǎng)絡(luò)流寫(xiě)入數(shù)據(jù),還是由服務(wù)端向網(wǎng)絡(luò)流寫(xiě)入數(shù)據(jù)。1. 客戶(hù)端開(kāi)辟數(shù)據(jù)端口用于偵聽(tīng),假設(shè)為8006。
6、2. 假設(shè)客戶(hù)端輸入了R1,則發(fā)送控制字符串:<protocol><file name="Server01.jpg" mode="receive" port="8006" /></protocol>到服務(wù)端。 3. 服務(wù)端收到以后,根據(jù)客戶(hù)端ip和端口號(hào)與該客戶(hù)端建立連接。 4. 客戶(hù)端建立起與服務(wù)端的連接,服務(wù)端開(kāi)始網(wǎng)絡(luò)流中寫(xiě)入數(shù)據(jù)。 5. 傳送完畢后服務(wù)端、客戶(hù)端分別關(guān)閉連接。 2.協(xié)議處理類(lèi)的實(shí)現(xiàn)和上面一章一樣,在開(kāi)始編寫(xiě)實(shí)際的服務(wù)端客戶(hù)端代碼之前,我們首先要編寫(xiě)處理協(xié)議的類(lèi),它需要提供這樣兩
7、個(gè)功能:1、方便地幫我們獲取完整的協(xié)議信息,因?yàn)榍懊嫖覀冋f(shuō)過(guò),服務(wù)端可能將客戶(hù)端的多次獨(dú)立請(qǐng)求拆分或合并。比如,客戶(hù)端連續(xù)發(fā)送了兩條控制信息到服務(wù)端,而服務(wù)端將它們合并了,那么則需要先拆開(kāi)再分別處理。2、方便地獲取我們所想要的屬性信息,因?yàn)閰f(xié)議是XML格式,所以還需要一個(gè)類(lèi)專(zhuān)門(mén)對(duì)XML進(jìn)行處理,獲得字符串的屬性值。2.1 ProtocalHandler輔助類(lèi)我們先看下ProtocalHandler,它與上一篇中的RequestHandler作用相同。需要注意的是必須將它聲明為實(shí)例的,而非靜態(tài)的,這是因?yàn)槊總€(gè)TcpClient都需要對(duì)應(yīng)一個(gè)ProtocalHandler,因?yàn)樗鼉?nèi)部維護(hù)的pati
8、alProtocal不能共享,在協(xié)議發(fā)送不完整的情況下,這個(gè)變量用于臨時(shí)保存被截?cái)嗟淖址?。public class ProtocolHandler private string partialProtocal; / 保存不完整的協(xié)議 public ProtocolHandler() partialProtocal = ""
9、0; public string GetProtocol(string input) return GetProtocol(input, null); / 獲得協(xié)議 private string GetProtocol(string input, List<string&
10、gt; outputList) if (outputList = null) outputList = new List<string>(); if (String.IsNullOrEmpty(input)
11、0; return outputList.ToArray(); if (!String.IsNullOrEmpty(partialProtocal) input = partialProtocal + input; string pattern = &
12、quot;(<protocol>.*?</protocol>)" / 如果有匹配,說(shuō)明已經(jīng)找到了,是完整的協(xié)議 if (Regex.IsMatch(input, pattern) / 獲取匹配的值
13、0; string match = Regex.Match(input, pattern).Groups0.Value; outputList.Add(match); partialProtocal = ""
14、 / 縮短input的長(zhǎng)度 input = input.Substring(match.Length); / 遞歸調(diào)用
15、GetProtocol(input, outputList); else / 如果不匹配,說(shuō)明協(xié)議的長(zhǎng)度不夠, / 那么先緩存,然后等待下一次請(qǐng)求
16、0; partialProtocal = input; return outputList.ToArray(); 因?yàn)楝F(xiàn)在它已經(jīng)不是本文的重點(diǎn)了,所以我就不演示對(duì)于它的測(cè)試了,本文所附帶的代碼中含有它的測(cè)試代碼(我在ProtocolHandler中添加了一個(gè)靜態(tài)類(lèi)Test())。2.2 FileRequestType枚舉和FileProtocol結(jié)構(gòu)因?yàn)閄ML是以字符
17、串的形式在進(jìn)行傳輸,為了方便使用,我們最好構(gòu)建一個(gè)強(qiáng)類(lèi)型來(lái)對(duì)它們進(jìn)行操作,這樣會(huì)方便很多。我們首先可以定義FileRequestMode枚舉,它代表是發(fā)送還是接收文件:public enum FileRequestMode Send = 0, Receive接下來(lái)我們?cè)俣x一個(gè)FileProtocol結(jié)構(gòu),用來(lái)為整個(gè)協(xié)議字符串提供強(qiáng)類(lèi)型的訪問(wèn),注意這里覆蓋了基類(lèi)的ToString()方法,這樣在客戶(hù)端我們就不需要再手工去編寫(xiě)XML,只要在結(jié)構(gòu)值上調(diào)用ToString()就OK了,會(huì)方便很多。public struct F
18、ileProtocol private readonly FileRequestMode mode; private readonly int port; private readonly string fileName; public FileProtocol (FileRequestMode mode, int port, string fileName)
19、60; this.mode = mode; this.port = port; this.fileName = fileName; public FileRequestMode Mode get re
20、turn mode; public int Port get return port; public string FileName get return fileName; public overr
21、ide string ToString() return String.Format("<protocol><file name="0" mode="1" port="2" /></protocol>", fileName, mode, port); 2.3 ProtocolHelper輔助類(lèi)這個(gè)類(lèi)專(zhuān)用于將XML格式的協(xié)議映射為我們上面定義的強(qiáng)類(lèi)型對(duì)象,這里我
22、沒(méi)有加入try/catch異常處理,因?yàn)閰f(xié)議對(duì)用戶(hù)來(lái)說(shuō)是不可見(jiàn)的,而且客戶(hù)端應(yīng)該總是發(fā)送正確的協(xié)議,我覺(jué)得這樣可以讓代碼更加清晰:public class ProtocolHelper private XmlNode fileNode; private XmlNode root; public ProtocolHelper(string protocol) Xml
23、Document doc = new XmlDocument(); doc.LoadXml(protocol); root = doc.DocumentElement; fileNode = root.SelectSingleNode("file");
24、/ 此時(shí)的protocal一定為單條完整protocal private FileRequestMode GetFileMode() string mode = fileNode.Attributes"mode".Value; mode = mode.ToLower(); if (mode
25、 = "send") return FileRequestMode.Send; else return FileRequestMode.Receive; /
26、獲取單條協(xié)議包含的信息 public FileProtocol GetProtocol() FileRequestMode mode = GetFileMode(); string fileName = "" int port = 0;
27、160; fileName = fileNode.Attributes"name".Value; port = Convert.ToInt32(fileNode.Attributes"port".Value); return new FileProtocol(mode, port, fileName); OK,我們又耽誤了點(diǎn)時(shí)間,下面就讓我們
28、進(jìn)入正題吧。3.客戶(hù)端發(fā)送數(shù)據(jù)3.1 服務(wù)端的實(shí)現(xiàn)我們還是將一個(gè)問(wèn)題分成兩部分來(lái)處理,先是發(fā)送數(shù)據(jù),然后是接收數(shù)據(jù)。我們先看發(fā)送數(shù)據(jù)部分的服務(wù)端。如果你從第一篇文章看到了現(xiàn)在,那么我覺(jué)得更多的不是技術(shù)上的問(wèn)題而是思路,所以我們不再將重點(diǎn)放到代碼上,這些應(yīng)該很容易就看懂了。class Server static void Main(string args) Console.WriteLine("Server is running . "); &
29、#160; IPAddress ip = IPAddress.Parse(""); TcpListener listener = new TcpListener(ip, 8500); listener.Start();
30、0; / 開(kāi)啟對(duì)控制端口 8500 的偵聽(tīng) Console.WriteLine("Start Listening ."); while (true) / 獲取一個(gè)連接,同步方法,在此處中斷
31、60; TcpClient client = listener.AcceptTcpClient(); RemoteClient wapper = new RemoteClient(client);
32、60; wapper.BeginRead(); public class RemoteClient private TcpClient client; private NetworkStream streamToClient; private const int BufferSize = 8192;
33、0; private byte buffer; private ProtocolHandler handler; public RemoteClient(TcpClient client) this.client = client; / 打印連接到的客戶(hù)端信息
34、 Console.WriteLine("nClient Connected!0 <- 1", client.Client.LocalEndPoint, client.Client.RemoteEndPoint); / 獲得流 stream
35、ToClient = client.GetStream(); buffer = new byteBufferSize; handler = new ProtocolHandler(); / 開(kāi)始進(jìn)行讀取 public void BeginRead()
36、; AsyncCallback callBack = new AsyncCallback(OnReadComplete); streamToClient.BeginRead(buffer, 0, BufferSize, callBack, null); / 再讀取完成時(shí)進(jìn)行回調(diào) private void OnReadC
37、omplete(IAsyncResult ar) int bytesRead = 0; try lock (streamToClient)
38、 bytesRead = streamToClient.EndRead(ar); Console.WriteLine("Reading data, 0 bytes .", bytesRead);
39、 if (bytesRead = 0) throw new Exception("讀取到0字節(jié)"); string msg = Encoding.Unicode.GetString(buffer, 0, bytesRead); Ar
40、ray.Clear(buffer,0,buffer.Length); / 清空緩存,避免臟讀 / 獲取protocol數(shù)組 string protocolArray = handler.GetProtocol(msg);
41、0; foreach (string pro in protocolArray) / 這里異步調(diào)用,不然這里可能會(huì)比較耗時(shí) Parameter
42、izedThreadStart start = new ParameterizedThreadStart(handleProtocol); start.BeginInvoke(pro, nul
43、l, null); / 再次調(diào)用BeginRead(),完成時(shí)調(diào)用自身,形成無(wú)限循環(huán) lock (streamToClient)
44、 AsyncCallback callBack = new AsyncCallback(OnReadComplete); streamToClient.BeginRead(buffer, 0, BufferSize, callBack, null); &
45、#160; catch(Exception ex) if(streamToClient!=null) streamToClient.Disp
46、ose(); client.Close(); Console.WriteLine(ex.Message); / 捕獲異常時(shí)退出程序
47、; / 處理protocol private void handleProtocol(object obj) string pro = obj as string; ProtocolHelper helper = new ProtocolHelper(pro); FileProtocol prot
48、ocol = helper.GetProtocol(); if (protocol.Mode = FileRequestMode.Send) / 客戶(hù)端發(fā)送文件,對(duì)服務(wù)端來(lái)說(shuō)則是接收文件 receiveFile(protocol);
49、60; else if (protocol.Mode = FileRequestMode.Receive) / 客戶(hù)端接收文件,對(duì)服務(wù)端來(lái)說(shuō)則是發(fā)送文件 / sendFile(protocol);
50、60; private void receiveFile(FileProtocol protocol) / 獲取遠(yuǎn)程客戶(hù)端的位置 IPEndPoint endpoint = client.Client.RemoteEndPoint as IPEndPoint; IPAd
51、dress ip = endpoint.Address; / 使用新端口號(hào),獲得遠(yuǎn)程用于接收文件的端口 endpoint = new IPEndPoint(ip, protocol.Port); / 連接到遠(yuǎn)程客戶(hù)端
52、; TcpClient localClient; try localClient = new TcpClient(); localClient.Connect(endpoint);
53、; catch Console.WriteLine("無(wú)法連接到客戶(hù)端 -> 0", endpoint); return;
54、160; / 獲取發(fā)送文件的流 NetworkStream streamToClient = localClient.GetStream(); / 隨機(jī)生成一個(gè)在當(dāng)前目錄下的文件名稱(chēng) string path =
55、160; Environment.CurrentDirectory + "/" + generateFileName(protocol.FileName); byte fileBuffer = new byte1024; / 每次收1KB FileStream fs = new FileStream(path, FileMode.CreateNew, FileAccess.Write);
56、; / 從緩存buffer中讀入到文件流中 int bytesRead; int totalBytes = 0; do bytesRead =
57、 streamToClient.Read(buffer, 0, BufferSize); fs.Write(buffer, 0, bytesRead); totalBytes += byte
58、sRead; Console.WriteLine("Receiving 0 bytes .", totalBytes); while (bytesRead > 0); Console.WriteLine("Total 0 bytes received, Done!
59、", totalBytes); streamToClient.Dispose(); fs.Dispose(); localClient.Close(); / 隨機(jī)獲取一個(gè)圖片名稱(chēng) private string generateF
60、ileName(string fileName) DateTime now = DateTime.Now; return String.Format( "0_1_2_3", now.Minute, now.Second, now.Millisecond, fileName
61、60; ); 這里應(yīng)該沒(méi)有什么新知識(shí),需要注意的地方有這么幾個(gè):· 在OnReadComplete()回調(diào)方法中的foreach循環(huán),我們使用委托異步調(diào)用了handleProtocol()方法,這是因?yàn)閔andleProtocol即將執(zhí)行的是一個(gè)讀取或接收文件的操作,也就是一個(gè)相對(duì)耗時(shí)的操作。 · 在handleProtocol()方法中,我們深切體會(huì)了定義ProtocolHelper類(lèi)和FileProtocol結(jié)構(gòu)的好處。如果沒(méi)有定義它們,這里將是不堪入目的處理XM
62、L以及類(lèi)型轉(zhuǎn)換的代碼。 · handleProtocol()方法中進(jìn)行了一個(gè)條件判斷,注意sendFile()方法我屏蔽掉了,這個(gè)還沒(méi)有實(shí)現(xiàn),但是我想你已經(jīng)猜到它將是后面要實(shí)現(xiàn)的內(nèi)容。 · receiveFile()方法是實(shí)際接收客戶(hù)端發(fā)來(lái)文件的方法,這里沒(méi)有什么特別之處。需要注意的是文件存儲(chǔ)的路徑,它保存在了當(dāng)前程序執(zhí)行的目錄下,文件的名稱(chēng)我使用generateFileName()生成了一個(gè)與時(shí)間有關(guān)的隨機(jī)名稱(chēng)。 3.2客戶(hù)端的實(shí)現(xiàn)我們現(xiàn)在先不著急實(shí)現(xiàn)客戶(hù)端S1、R1等用戶(hù)菜單,首先完成發(fā)送文件這一功能,實(shí)際上,就是為上一節(jié)SendMessage()加一個(gè)姐妹方法Send
63、File()。class Client static void Main(string args) ConsoleKey key; ServerClient client = new ServerClient(); string filePath = Environment.CurrentDirectory
64、 + "/" + "Client01.jpg" if(File.Exists(filePath) client.BeginSendFile(filePath); Consol
65、e.WriteLine("nn輸入"Q"鍵退出。"); do key = Console.ReadKey(true).Key; while (key != ConsoleKey.Q); public class ServerClie
66、nt private const int BufferSize = 8192; private byte buffer; private TcpClient client; private NetworkStream streamToServer; public ServerClient() try
67、160; client = new TcpClient(); client.Connect("localhost", 8500); / 與服務(wù)器連接 catch (Exception ex)
68、160; Console.WriteLine(ex.Message); return; buffer = new byteBufferSize;
69、; / 打印連接到的服務(wù)端信息 Console.WriteLine("Server Connected!0 -> 1", client.Client.LocalEndPoint, client.Client.RemoteEndPoint); stre
70、amToServer = client.GetStream(); / 發(fā)送消息到服務(wù)端 public void SendMessage(string msg) byte temp = Encoding.Unicode.GetBytes(msg); / 獲得緩存 try &
71、#160; lock (streamToServer) streamToServer.Write(temp, 0, temp.Length); / 發(fā)往服務(wù)器
72、60; Console.WriteLine("Sent: 0", msg); catch (Exception ex) Console.WriteLine(ex.Message); &
73、#160; return; / 發(fā)送文件 - 異步方法 public void BeginSendFile(string filePath) ParameterizedThreadStart start =
74、160; new ParameterizedThreadStart(BeginSendFile); start.BeginInvoke(filePath, null, null); private void BeginSendFile(object obj) string filePath = obj as
75、 string; SendFile(filePath); / 發(fā)送文件 - 同步方法 public void SendFile(string filePath) IPAddress ip = IPAddress.Parse(""); &
76、#160; TcpListener listener = new TcpListener(ip, 0); listener.Start(); / 獲取本地偵聽(tīng)的端口號(hào) IPEndPoint endPoint = listener.LocalEndpoint as IPEndPoint; &
77、#160; int listeningPort = endPoint.Port; / 獲取發(fā)送的協(xié)議字符串 string fileName = Path.GetFileName(filePath); FileProtocol protocol =
78、60; new FileProtocol(FileRequestMode.Send, listeningPort, fileName); string pro = protocol.ToString(); SendMessage(pro); / 發(fā)送協(xié)議到服務(wù)端 &
79、#160; / 中斷,等待遠(yuǎn)程連接 TcpClient localClient = listener.AcceptTcpClient(); Console.WriteLine("Start sending file."); NetworkStream stream = localClient
80、.GetStream(); / 創(chuàng)建文件流 FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read); byte fileBuffer =
81、 new byte1024; / 每次傳1KB int bytesRead; int totalBytes = 0; / 創(chuàng)建獲取文件發(fā)送狀態(tài)的類(lèi) SendStatus status = new SendStatus
82、(filePath); / 將文件流轉(zhuǎn)寫(xiě)入網(wǎng)絡(luò)流 try do Thread.Sleep(10);
83、60; / 為了更好的視覺(jué)效果,暫停10毫秒:-) bytesRead = fs.Read(fileBuffer, 0, fileBuffer.Length);
84、0; stream.Write(fileBuffer, 0, bytesRead); totalBytes += bytesRead;
85、0; / 發(fā)送了的字節(jié)數(shù) status.PrintStatus(totalBytes); / 打印發(fā)送狀態(tài) while (bytesRead > 0);
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶(hù)所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶(hù)上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶(hù)上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶(hù)因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 筆譯職業(yè)發(fā)展方向
- 腦血管疾病患者的社區(qū)康復(fù)與護(hù)理
- 骨質(zhì)疏松癥的高危人群識(shí)別與管理
- 分部介紹教學(xué)課件
- 行業(yè)銷(xiāo)售管理工具與銷(xiāo)售預(yù)測(cè)模板
- 成都市新津區(qū)牧山新城小學(xué)公開(kāi)招聘儲(chǔ)備教師及答案詳解(考點(diǎn)梳理)
- 2026重慶雙福農(nóng)產(chǎn)品批發(fā)市場(chǎng)有限公司招聘3人備考題庫(kù)及1套參考答案詳解
- 骨質(zhì)疏松癥的治療效果評(píng)估與監(jiān)測(cè)
- 胎兒電子監(jiān)護(hù)與母體舒適度
- 配電線路知識(shí)培訓(xùn)課件
- (一診)重慶市九龍坡區(qū)區(qū)2026屆高三學(xué)業(yè)質(zhì)量調(diào)研抽測(cè)(第一次)物理試題
- 2026年榆能集團(tuán)陜西精益化工有限公司招聘?jìng)淇碱}庫(kù)完整答案詳解
- 2026廣東省環(huán)境科學(xué)研究院招聘專(zhuān)業(yè)技術(shù)人員16人筆試參考題庫(kù)及答案解析
- 邊坡支護(hù)安全監(jiān)理實(shí)施細(xì)則范文(3篇)
- 6.1.3化學(xué)反應(yīng)速率與反應(yīng)限度(第3課時(shí) 化學(xué)反應(yīng)的限度) 課件 高中化學(xué)新蘇教版必修第二冊(cè)(2022-2023學(xué)年)
- 北京市西城區(qū)第8中學(xué)2026屆生物高二上期末學(xué)業(yè)質(zhì)量監(jiān)測(cè)模擬試題含解析
- 2026年遼寧輕工職業(yè)學(xué)院?jiǎn)握芯C合素質(zhì)考試參考題庫(kù)帶答案解析
- 2026屆北京市清華大學(xué)附中數(shù)學(xué)高二上期末調(diào)研模擬試題含解析
- 醫(yī)院實(shí)習(xí)生安全培訓(xùn)課課件
- 2026年保安員理論考試題庫(kù)
- 四川省成都市武侯區(qū)西川中學(xué)2024-2025學(xué)年八上期末數(shù)學(xué)試卷(解析版)
評(píng)論
0/150
提交評(píng)論