Socket Server And Client:

1、socket 架构图:

socket客户端端口固定java socket 客户端端口_Text

2、端口的分类:

1)公认端口(well known ports):从0到1023,它们紧密绑定(binding)于一些服务。通常这些端口的通讯明确表明了某种服务的协议。例如:80 端口实际上总是HTTP通讯。

2)注册端口(registered ports):从1024到49151。它们松散的邦定于一些服务。也就是说有许多服务邦定于这些端口,这些端口同样用于许多其他目的。例如:许多系统处理动态端口从1024左右开始。

3)动态和/或者私有端口(Dynamic and/or private ports):从49152到65535。理论上,不应该为服务分配这些端口。实际上,机器通常从1024起分配动态端口。但也有例外的情况。

3、Socket Server:

 

 

public List<Socket> proxSockets = new List<Socket>();
         public SocketServer()
         {
             InitializeComponent();
         }        private void btn_Listen_Click(object sender, RoutedEventArgs e)
         {
             //1、创建服务器的socket
             Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
             //Log 创建了服务器socket对象
             this.txt_Log.Text = "创建了服务器Socket\r\n" + txt_Log.Text;
             //2、绑定IP和端口
             IPAddress ip = IPAddress.Parse(txt_IP.Text);
             IPEndPoint endPoint = new IPEndPoint(ip, Convert.ToInt32(txt_port.Text));
             serverSocket.Bind(endPoint);
             //3、开始侦听,这个10表示等待连接的队列大小,例如:同一时间来了100个连接,处理一个,另外99个有10个放入队列,剩下的报错
             serverSocket.Listen(10);
             //4、接受客户端的connect,Accept 方法会阻塞当前线程,为防止阻塞主线程,因此放到线程池执行
             this.txt_Log.Text = "开始接受客户端连接\r\n" + txt_Log.Text;
             ThreadPool.QueueUserWorkItem(new WaitCallback(StartAcceptClient), serverSocket);
         }        private void StartAcceptClient(object state)
         {
             Socket serverSocket = state as Socket;
             //可能有多个client 连接
             while (true)
             {
                 Socket proxSocket = serverSocket.Accept();
                 proxSockets.Add(proxSocket);
                 //并且代理socket 对象需要接受client 的Message
                 ThreadPool.QueueUserWorkItem(new WaitCallback(RecevieData), proxSocket);
                 关闭代理socket (看实际应用场景决定)
                 //proxSocket.Shutdown(SocketShutdown.Both);
                 //proxSocket.Close();
             }        }
        private void RecevieData(object state)
         {
             Socket proxSocket = state as Socket;
             byte[] data = new byte[1024 * 1024];
             //每一个代理都需要接受
             while (true)
             {
                 //try catch  防止客户端异常退出
                 try
                 {
                     int realLen = proxSocket.Receive(data, 0, data.Length, SocketFlags.None);
                     if (realLen == 0)
                     {
                         //对方正常退出的case,对方有shutdown
                         StopConnect(proxSocket);
                         
                         proxSockets.Remove(proxSocket);
                         return;
                     }
                 }
                 catch (Exception ex)
                 {
                     //异常退出也要关闭
                     StopConnect(proxSocket);
                     throw ex;
                 }
                 
             }
         }        private void StopConnect(Socket proxSocket)
         {
             if (proxSocket.Connected)
             {
                 proxSocket.Shutdown(SocketShutdown.Both);
                 //超过100s 强制关闭
                 proxSocket.Close(100);
             }
         }        //群发到每一个client
         private void btn_Send_Click(object sender, RoutedEventArgs e)
         {
             foreach (var item in proxSockets)
             {
                 if (item.Connected)
                 {
                     string str = this.txt_port.Text.Trim().ToUpper();
                     byte[] data = Encoding.Default.GetBytes(str);
                     item.Send(data, 0, data.Length, SocketFlags.None);
                 }
             }
         }

 

 

 

4、socket Client:

public Socket ClientSocket { get; set; }
         public SocketClient()
         {
             InitializeComponent();
         }        private void btn_Connect_Click(object sender, RoutedEventArgs e)
         {
             //1、创建服务器的socket
             Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
             ClientSocket = clientSocket;
             //2、连接到服务器
             while (true)
             {
                 try
                 {
                     clientSocket.Connect(IPAddress.Parse(txt_IP.Text), Convert.ToInt32(txt_port.Text));
                     break;
                 }
                 catch (Exception)
                 {
                     //Log 连接失败 并重新连接
                 }
             }            //连接OK 那个socket 开始receive
             Thread th = new Thread(new ParameterizedThreadStart(ReceiveData));
             th.IsBackground = true;
             th.Start(ClientSocket);
         }        private void ReceiveData(object obj)
         {
             Socket socket = obj as Socket;
             byte[] data = new byte[1024 * 1024];
             //每一个代理都需要接受
             while (true)
             {
                 //try catch  防止客户端异常退出
                 try
                 {
                     int realLen = socket.Receive(data, 0, data.Length, SocketFlags.None);
                     if (realLen == 0)
                     {
                         //对方正常退出的case,对方有shutdown
                         StopConnect(socket);
                                                
                         return;
                     }
                 }
                 catch (Exception ex)
                 {                    throw ex;
                 }            }
         }        private void StopConnect(Socket socket)
         {
             if (socket.Connected)
             {
                 socket.Shutdown(SocketShutdown.Both);
                 socket.Close(100);
             }           
         }        private void btn_Send_Click(object sender, RoutedEventArgs e)
         {
             if (ClientSocket.Connected)
             {
                 string str = this.txt_port.Text.Trim().ToUpper();
                 byte[] data = Encoding.Default.GetBytes(str);
                 ClientSocket.Send(data, 0, data.Length, SocketFlags.None);
             }
         }
     }

 

 

 

5、Socket的通信的本质&阻塞:

send方法把数据复制到发送缓冲区中,它做的事情只是这个,然后TCP协议底层就根据在TCP三步握手时确定的MSS大小(比如:1024字节)从发送缓冲区中取1024字节放到TCP数据包的数据部分,然后从发送缓冲区中删除1024个字节。并且TCP不是真正意义上的停止等待协议。也就是并不是发送一个TCP数据包就停止发送TCP数据包,直到收到接收方发送得ACK数据包才发送下一个TCP数据包。而Receive 则是从接收缓冲区中取数据。那么根据这个原理

阻塞原因

产生阻塞的原因可能是下面几个:
第一:你的发送缓冲区太小了。比如:只有1MB或者小于1MB,那么你的发送缓冲区会被迅速填满。导致阻塞
第二: 对方的网络环境很差,接收方的接收缓冲区太小了.你的发送缓冲区发送速度就很慢。发送缓冲区的数据清空速度就很慢。
第三:整个网路环境很差.数据要经过很多路由器。路由器很有自己的缓冲区,路由器的缓冲区如果被填满,那么你的发送数据就降低。你的发送缓冲区清空数据的速度就降低。连续三次发1MB的速度就迅速填满发送缓冲区。

 

6、Socket的可能问题:

由于第五点我们知道,socket本质是通过基础系统的空间来交换数据的,那么主要可能引发以下两点问题

 

1,Socket receive的实际字节数不等于预期接收的字节数

receive时,虽然我们给Buffer定义了一个长度和要接收到的size,但是Socket接收到的字节数(即返回值)并不一定等于Size

通常我们会用一个较大的size来接收,另外需要采用循环接受的办法,上面的代码

 

2,服务器发送多次,客户端一次接收的问题。(理论上设置的receive buffer 足够大,可以一次拿到基础系统空间的数据即所有的森send)

存在一个问题:假如客户端想一次接收服务器多次发送过来的数据,客户端定义缓存body的长度等于服务端多次发送的数据长度和,客户端在服务器发送完成后开始一次接收,客户端肯定能接收到服务器发送过来的所有数据,不会只接收服务器发送过来的部分数据。

打个比方,假如服务器分两次分别发送“Hello”,“World”。这样客户端一定能接受到“HelloWorld”。

这样有可能会导致如果需要一条send 一条receive的情况(实时聊天工具或者工业上的设备间通信),就很难处理。