核心:
在服务器端和客户端的两个Socket实例,共同维持一个连接,而我们还需要一个服务端绑定了特定端口号的固定的serverSocket,用来监听远方clientSocket的申请,并为这个申请建立服务端对应的proxSocket
服务器维护:serverSocket
服务端实例客户端实例关系proxSocketclientSocket一一对应微软官方文档
一、要有服务端
--配置--
1、new Socket
Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
2、Bind
ServerSocket.Bind(new IPEndPoint(IPAddress.Parse(txtIP), int.Parse(txtPost))); //服务器绑定本机IP和端口
3、Listen
ServerSocket.Listen(10); //最大连接数是10
4、Accept
Socket proxSocket = ServerSocket.Accept(); //监听Socket连接行为,并为监听到的链接创建Socket实例,会阻塞线程直到端口链接
--信息发送与传输--
5、Receive
proxSocket.Receive(data, 0, data.Length, SocketFlags.None); //data是要写入的byte数组,会阻塞线程直到侦听到slientSocket的Send并持续到IO结束
6、Send
proxSocket.Send(result, 0, result.Length, SocketFlags.None); //result是要上传的byte数组
二、还有客户端
--配置--
1、new Socet
ClientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
2、Connect
ClientSocket.Connect(new IPEndPoint(IPAddress.Parse(txtIP), int.Parse(txtPort))); //尝试链接服务器的相应IP和端口,连接成功后,服务器端创建一个特定的proxSocket用来进行信息交换
--信息发送与传输--
3
ClientSocket.Receive(data, 0, data.Length, SocketFlags.None);
4
ClientSocket.Send(result, 0, result.Length, SocketFlags.None);
三、简单实现
- using System;
- using System.Net;
- using System.Net.Sockets;
- using System.Text;
- namespace SockerDamo
- {
- class SocketServer
- {
- List<Socket> ClientProxSocketList = new List<Socket>();//用于存放客户端链接
- Socket ServerSocket { get; set; }
- public void Start()//创建服务器Socket,开始侦听客户端,并开始循环接收消息
- {
- //1.创建socket对象
- Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
- ServerSocket = serverSocket;
- //first is 寻址方式(此处是Ipv4)
- //second is the socket's type
- //And the thrid is the 传输协议
- System.Console.WriteLine("请输入IP地址:");
- String txtIP = Console.ReadLine();
- System.Console.WriteLine("请输入端口号:");
- String txtPost = Console.ReadLine();
- //2.绑定端口IP
- ServerSocket.Bind(new IPEndPoint(IPAddress.Parse(txtIP), int.Parse(txtPost)));
- //socket's Bind action need a IPEndPoint to bind the socket and the computer's ip and post
- //so in the IPEndPoint we need a IPAddress and a int number(Post)
- //3.开始侦听
- ServerSocket.Listen(20);//the number 表示 同时排队的最大限制数量
- //同时来了100个链接请求,只能处理一个链接,队列里面放20个等待链接的客户端,其他的返回错误消息。
- //4.开始接受客户端的链接
- //为了不阻塞主线程,我们应该把以下代码放在一个新的线程(池)中
- try
- {
- System.Console.WriteLine("开始监听链接...");
- Socket proxSocket = ServerSocket.Accept();//这个方法会阻塞当前线程,直到监听到链接
- AppendTextToTxtLog(string.Format("客户端{0}已链接", proxSocket.RemoteEndPoint.ToString()));
- byte[] data = new byte[1024 * 1024 * 256];//用来放数据的数组
- int len;
- while (true)
- {
- System.Console.WriteLine("请选择模式:");
- System.Console.WriteLine("0.等待接收消息");
- System.Console.WriteLine("1.发送消息");
- string mo = Console.ReadLine();
- //获取客户端数据并返回读取的字节数,会阻塞当前线程,
- //当客户端突然掉线,往往会引发异常
- if (mo == "0")
- {
- try
- {
- len = proxSocket.Receive(data, 0, data.Length, SocketFlags.None);//往data数组里,从index=0开始,最长写入数据长度为data.Length
- if (data[0] == 0)
- {
- StopConnect(proxSocket);
- }//正常退出逻辑
- else if (data[0] == 1)
- {
- string str = Encoding.UTF8.GetString(data, 1, len - 1);//在data数组中从0开始,len个数据,转成str
- AppendTextToTxtLog(string.Format("接收到客户端:{0} 的信息是:{1}", proxSocket.RemoteEndPoint.ToString(), str));
- }
- }
- catch (Exception)
- {
- Console.WriteLine("接收数据出错");
- StopConnect(proxSocket);
- }
- }
- else if (mo == "1")
- {
- SendMsg();
- }
- }
- }
- catch
- {
- AppendTextToTxtLog("出问题啦:您在接收客户端的请求的时候,发生了异常,夭寿啦```");
- }
- }
- private void StopConnect(Socket proxSocket)//停止链接
- {
- try
- {
- if (proxSocket.Connected)
- {
- proxSocket.Shutdown(SocketShutdown.Both);
- proxSocket.Close(100);
- }
- }
- catch (Exception ex)
- {
- System.Console.WriteLine("或许没有成功的停止连接" + ex.ToString());
- }
- }
- //发送消息
- private void SendMsg()
- {
- String txtMsg = Console.ReadLine();
- foreach (var proxSocket in ClientProxSocketList)
- {
- if (proxSocket.Connected)
- {
- byte[] data = Encoding.UTF8.GetBytes(txtMsg);//信息转二进制
- byte[] result = new byte[data.Length + 1];//信息的二进制放在1~data.Length
- result[0] = 1;//第0个位置是标志位,将来我们可以用这个标志位,分辨文件类型,将来用来传文件
- Buffer.BlockCopy(data, 0, result, 1, data.Length);//把 data从0 转 result从1 长度data.Length
- proxSocket.Send(result, 0, result.Length, SocketFlags.None);//发送消息
- }
- }
- AppendTextToTxtLog(string.Format("{0}(本机) 的信息是:{1}", ServerSocket.LocalEndPoint.ToString(), txtMsg));
- }
- private void AppendTextToTxtLog(string txt)
- {
- Console.WriteLine(txt);
- }
- }
- class SocketClient
- {
- Socket ClientSocket { get; set; }
- public void Start()//创建客户端Socket,并开始循环接收消息
- {
- #region 获取服务器端口内容
- System.Console.WriteLine("请输入服务器IP:");
- String txtIP = Console.ReadLine();
- System.Console.WriteLine("请输入端口号:");
- String txtPort = Console.ReadLine();
- #endregion
- //客户端链接服务器端
- //1.创建Socket对象
- ClientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
- //2.连接服务器端Socket
- try//如果服务器的Listen队列已满,那么就会返回一个异常
- {
- ClientSocket.Connect(new IPEndPoint(IPAddress.Parse(txtIP), int.Parse(txtPort)));
- }
- catch
- {
- System.Console.WriteLine("当前服务器无法连接");
- //Thread.Sleep(1000);
- return;
- }
- //3.接收服务器端消息
- byte[] data = new byte[1024 * 1024 * 256];//传输数据放在这里,这里是256MB = 256 * 1024 KB = 256 * 1024 * 1024Byte
- int len;
- string str;
- string wenJianMing = "";
- while (true)
- {
- System.Console.WriteLine("请选择模式:");
- System.Console.WriteLine("0.等待接收消息");
- System.Console.WriteLine("1.发送消息");
- string mo = Console.ReadLine();
- len = 0;
- str = null;
- if (mo == "0")
- try
- {
- len = ClientSocket.Receive(data, 0, data.Length, SocketFlags.None);//获取服务器端数据并返回读取的字节数,会阻塞当前线程,
- //当客户端突然掉线,往往会引发异常
- if (data[0] == 0)//模式0退出
- {
- AppendTextToTxtLog(string.Format("服务端:{0} 正常退出", ClientSocket.RemoteEndPoint.ToString()));
- StopConnect();
- }
- else if (data[0] == 1)
- {//模式1收到了字符串
- str = Encoding.UTF8.GetString(data, 1, len - 1);
- AppendTextToTxtLog(string.Format("Socket信息:{0}", str));
- }
- //一次类推,总共有256种消息的传输模式
- }
- catch (Exception)
- {
- AppendTextToTxtLog(string.Format("服务端:{0} 非正常退出",
- ClientSocket.RemoteEndPoint.ToString()));
- StopConnect();
- return;
- }
- else if(mo == "1"){
- SendMsg();
- }
- }
- // 也可以将第3步写入方法ReceiveData
- // Thread thread = new Thread(new ParameterizedThreadStart(ReceiveData));
- // thread.IsBackground = true;
- // thread.Start(); // 然后开启线程
- }
- private void AppendTextToTxtLog(string txt)
- {
- Console.WriteLine(txt);
- }
- private void StopConnect()
- {
- try
- {
- if (ClientSocket.Connected)
- {
- ClientSocket.Shutdown(SocketShutdown.Both);
- ClientSocket.Close(100);
- }
- }
- catch (Exception ex)
- {
- System.Console.WriteLine("或许没有成功的停止连接" + ex.ToString());
- }
- }
- public void SendMsg()
- {
- if (ClientSocket.Connected)
- {
- System.Console.WriteLine("请输入要发送信息的模式:");
- System.Console.WriteLine("0:结束");
- System.Console.WriteLine("1:字符串");
- String ms = Console.ReadLine();
- if (ms == "0") { }
- if (ms == "1")
- {
- System.Console.WriteLine("请输入要发送的消息:");
- String s = Console.ReadLine();
- byte[] data = Encoding.UTF8.GetBytes(s);
- byte[] result = new byte[data.Length + 1];//信息的二进制放在1~data.Length
- result[0] = 1;//第0个位置是标志位,将来我们可以用这个标志位,分辨文件类型,将来用来传文件
- Buffer.BlockCopy(data, 0, result, 1, data.Length);//把 data从0 转 result从1 长度data.Length
- ClientSocket.Send(result, 0, result.Length, SocketFlags.None);//发送消息
- AppendTextToTxtLog(string.Format("本机的信息是:{0}", s));
- }
- }
- }
- }
- internal class Program
- {
- static void Main(string[] args)
- {
- System.Console.WriteLine("0:服务器端");
- System.Console.WriteLine("1:客户端");
- string ms = Console.ReadLine();
- if (ms == "0")
- {
- SocketServer server = new SocketServer();
- server.Start();
- }
- else if (ms == "1")
- {
- SocketClient client = new SocketClient();
- client.Start();
- }
- }
- }
- }
复制代码 来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |