第10章 网络编程
10.1网络编程基本概念
10.2 基本操作
10.2.1服务端对端口进行侦听
netstat -a
10.2.2 客户端与服务端连接
1.单一客户端与服务端连接
2.多个客户端与服务端连接
10.2.3 服务端获取客户端连接
1.获取单一客户端连接
2.获取多个客户端连接
10.3 同步传输字符串
1、使用socket建立连接后,客户端和服务端只要有一方使用close()或者dispose()关闭连接,对端在发送或接收时都会抛出异常:远程主机强迫关闭了一个现有的连接。
2、使用TcpClient建立连接后,当客户端在TcpClient实例上调用close()方法,或者在流上调用dispose()方法时:
(1)服务端调用read()方法会持续返回0,但不会抛出异常,所以会产生无限循环,需要break出循环;
(2)服务端调用write()方法会抛出异常:无法将数据写入传输连接: 您的主机中的软件中止了一个已建立的连接。。
(3)如果直接关闭掉客户端,或者客户端执行完毕没有调用stream.dispose()或者TcpClient.Close(),则在调用read()方法时会抛出异常: 无法从传输连接中读取数据: 远程主机强迫关闭了一个现有的连接。。
3、使用TcpClient建立连接后,当服务端在TcpClient实例上调用close()方法,或者在流上调用dispose()方法时:
(1)客户端调用write()方法会抛出异常:无法将数据写入传输连接: 您的主机中的软件中止了一个已建立的连接。。
(2)如果直接关闭掉服务端,则调用write()方法会抛出异常:无法将数据写入传输连接: 远程主机强迫关闭了一个现有的连接。。
4、创建udp广播套接字需要调用SetSocketOption,否则会抛出一场错误。udpSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1);
10.4 中英文字符大小和文本边界问题
ascii不能保存中文
unicode和utf8都是变长编码。对ascii字符编码,utf8占1字节,unicode占2字节,第2字节补零;对中文编码,utf8占3字节,unicode占2字节(169)
10.4.2 文本边界问题
当通过networkstream写入数据时,数据并没有立即发往远程主机,而是保存在TCP缓存中,经过一段时间后才进行发送。所以接收端可能产生合并数据或者分裂数据的情况。
10.5 异步传输字符串
10.6 文件传输
服务端程序:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Net.Sockets; using System.Net; namespace Server { class Program { static void Main(string[] args) { Console.WriteLine("Server is running..."); TcpListener listener = new TcpListener(IPAddress.Parse("192.168.10.14"), 8500); listener.Start(); Console.WriteLine("Start listening..."); while (true) { TcpClient client = listener.AcceptTcpClient(); Server server = new Server(client); server.BeginRead(); } } } }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Net.Sockets; using Protocol; using System.Threading; using System.Net; using System.IO; namespace Server { public class Server { private TcpClient client; private NetworkStream streamToClient; private const int bufferSize = 8192; private byte[] buffer; private ProtocolHandler handler; public Server(TcpClient client) { this.client = client; Console.WriteLine("\nClient connected!Local;{0}<--Client;{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 { bytesRead = streamToClient.EndRead(ar); Console.WriteLine("Reading data,{0} bytes...", bytesRead); if (bytesRead == 0) { Console.WriteLine("Client offline."); return; } string msg = Encoding.Unicode.GetString(buffer); 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); Thread th = new Thread(HandleProtocol); th.Start(pro); } 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 o) { string pro = o 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 SendFile(FileProtocol protocol) { throw new NotImplementedException(); } private void ReceiveFile(FileProtocol protocol) { 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 + "/" + GernerateFileName(protocol.FileName); byte[] fileBuffer = new byte[1024]; FileStream fs = new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write); int bytesRead; int totalBytes = 0; try { do { bytesRead = streamToClient.Read(buffer, 0, bufferSize); fs.Write(buffer, 0, bytesRead); totalBytes += bytesRead; Console.WriteLine("Receiving {0} bytes...", totalBytes); } while (bytesRead > 0); Console.WriteLine("Total {0} bytes received,Done!", totalBytes); } catch (Exception ex) { Console.WriteLine(ex.Message); } finally { streamToClient.Dispose(); fs.Dispose(); localClient.Close(); } } private string GernerateFileName(string fileName) { DateTime now = DateTime.Now; return string.Format("{0}_{1}_{2}_{3}", now.Minute, now.Second, now.Millisecond, fileName); } } }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Text.RegularExpressions; namespace Protocol { public class ProtocolHandler { private string partialProtocal; public ProtocolHandler() { partialProtocal = ""; } public string[] GetProtocol(string input) { return GetProtocol(input, null); } private string[] GetProtocol(string input, List<string> outputList) { if (outputList == null) { outputList = new List<string>(); } if (string.IsNullOrEmpty(input)) { return outputList.ToArray(); } if (!string.IsNullOrEmpty(partialProtocal)) { input = partialProtocal + input; } string pattern = "(^<protocol>.*?</protocol>)"; if (Regex.IsMatch(input, pattern)) { string match = Regex.Match(input, pattern).Groups[0].Value; outputList.Add(match); partialProtocal = ""; input = input.Substring(match.Length); GetProtocol(input, outputList); } else { partialProtocal = input; } return outputList.ToArray(); } } }
客户端程序:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
using System; using System.Collections.Generic; using System.Linq; using System.Text; using Protocol; using System.IO; namespace Client { class Program { static void Main(string[] args) { ConsoleKey key; Client c = new Client(); string filePath = Environment.CurrentDirectory + "/" + "李潇.jpg"; if (File.Exists(filePath)) { c.BeginSendFile(filePath); } Console.WriteLine("\n 输入\"Q\"键退出。"); do { key = Console.ReadKey(true).Key; } while (key != ConsoleKey.Q); } } }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Net.Sockets; using System.Threading; using System.Net; using System.IO; using Protocol; namespace Client { public class Client { private const int bufferSize = 8192; private byte[] buffer; private TcpClient client; private NetworkStream streamToServer; public Client() { try { client = new TcpClient(); client.Connect("192.168.10.14", 8500); } catch(Exception ex) { Console.WriteLine(ex.Message); return; } buffer = new byte[bufferSize]; streamToServer = client.GetStream(); Console.WriteLine("Server Connected! Local:{0}-->Server:{1}", client.Client.LocalEndPoint, client.Client.RemoteEndPoint); } public void SendMessage(string msg) { byte[] temp = Encoding.Unicode.GetBytes(msg); try { if (streamToServer == null) { return; } streamToServer.Write(temp, 0, temp.Length); Console.WriteLine("Sent:{0}", msg); } catch (Exception ex) { Console.WriteLine(ex.Message); } } public void BeginSendFile(string filePath) { //ParameterizedThreadStart start = new ParameterizedThreadStart(BeginSendFile); //start.BeginInvoke(filePath, null, null); Thread th = new Thread(BeginSendFile); th.Start(filePath); } private void BeginSendFile(object o) { string filePath = o as string; SendFile(filePath); } public void SendFile(string filePath) { IPAddress ip = IPAddress.Parse("192.168.10.14"); 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]; int bytesRead; int totalBytes = 0; SendStatus status = new SendStatus(filePath); try { do { //Thread.Sleep(100); 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 (Exception ex) { Console.WriteLine(ex.Message); } finally { fs.Dispose(); stream.Dispose(); localClient.Close(); listener.Stop(); } } } public class SendStatus { private FileInfo info; private long fileBytes; public SendStatus(string filePath) { info = new FileInfo(filePath); this.fileBytes = info.Length; } public void PrintStatus(int sent) { string percent = GetPercent(sent); Console.WriteLine("Sending {0} bytes,{1}%...", sent, percent); } public string GetPercent(int sent) { decimal allBytes = Convert.ToDecimal(fileBytes); decimal currenSent = Convert.ToDecimal(sent); decimal percent = (currenSent / allBytes) * 100; percent = Math.Round(percent, 1); if (percent.ToString() == "100.0") { return "100"; } return percent.ToString(); } } }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Xml; namespace Protocol { public class ProtocolHelper { private XmlNode fileNode; private XmlNode root; public ProtocolHelper(string protocol) { XmlDocument doc = new XmlDocument(); doc.LoadXml(protocol); root = doc.DocumentElement; fileNode = root.SelectSingleNode("file"); } private FileRequestMode GetFileMode() { string mode = fileNode.Attributes["mode"].Value; mode = mode.ToLower(); if (mode == "send") { return FileRequestMode.Send; } else { return FileRequestMode.Receive; } } public FileProtocol GetProtocol() { FileRequestMode mode = GetFileMode(); int port = Convert.ToInt32(fileNode.Attributes["port"].Value); string fileName = fileNode.Attributes["name"].Value; return new FileProtocol(mode, port, fileName); } } public enum FileRequestMode { Send = 0, Receive = 1 } public struct FileProtocol { private readonly FileRequestMode mode; private readonly int port; private readonly string fileName; public FileProtocol(FileRequestMode mode, int port, string fileName) { this.mode = mode; this.port = port; this.fileName = fileName; } public FileRequestMode Mode { get { return mode; } } public int Port { get { return port; } } public string FileName { get { return fileName; } } public override string ToString() { return string.Format("<protocol><file mode=\"{0}\" port=\"{1}\" name=\"{2}\" /></protocol>", mode, port, fileName); } } }