第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 文件传输
服务端程序:
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();
            }
        }
    }
}
View Code
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);
        }
    }
}
View Code
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();
        }
    }
}
View Code

客户端程序:

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);
        }
    }
}
View Code
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();
        }
    }
}
View Code
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);
        }
    }
}
View Code

 

posted on 2016-04-18 16:56  liuslayer  阅读(269)  评论(0编辑  收藏  举报

导航