zoukankan      html  css  js  c++  java
  • 两端通信

    上篇博文:http://www.cnblogs.com/wolf-sun/p/3329558.html

         介绍了客户端连接服务端,一对一,多对一的情况,下面实现服务器接收消息的功能。LZ这些弄的比较慢,也是边学习,边动手实现的。具体步骤在注释中写的比较清楚,不懂的可以留言,LZ会尽快回复。共同学习,共同进步。

    接收消息时机

          什么时候接收消息?当服务器开始监听,有客户端连接,并且连接成功,此时负责通信的Socket已经创建,此时就可以接收消息了,可以通过Socket的Receive()方法接收消息。

     View Code

    // 摘要:
    // 从绑定的 System.Net.Sockets.Socket 套接字接收数据,将数据存入接收缓冲区。
    //
    // 参数:
    // buffer:
    // System.Byte 类型的数组,它是存储接收到的数据的位置。
    //
    // 返回结果:
    // 接收到的字节数。
    //
    // 异常:
    // System.ArgumentNullException:
    // buffer 为 null。
    //
    // System.Net.Sockets.SocketException:
    // 试图访问套接字时发生错误。 有关更多信息,请参见备注部分。
    //
    // System.ObjectDisposedException:
    // System.Net.Sockets.Socket 已关闭。
    //
    // System.Security.SecurityException:
    // 调用堆栈中的调用方没有所需的权限。
    public int Receive(byte[] buffer);

         上面代码介绍了Receive方法接收参数及返回值。

    复制代码
     1  private void ListenConn(object o)
     2         {
     3             //将参数o 转化为监听的socket
     4             Socket socketListener = o as Socket;
     5             //写入循环 每一个连接就创建一个通信用的socket
     6             while (true)
     7             {
     8                 //当有客户端连接成功 创建通信用的socket
     9                 Socket connSocket = socketListener.Accept();
    10                 string ip = connSocket.RemoteEndPoint.ToString();
    11                 ShowMsg(ip + " " + DateTime.Now.ToString() + " 连接成功");
    12                //创建一个新线程去接收消息
    13                 Thread th = new Thread(ReceiveMsg);
    14                 th.Start(connSocket);
    15 
    16             }
    17 
    18 }
    复制代码

    接收消息的代码:

    复制代码
     1   //接收客户端的消息
     2         private void ReceiveMsg(object o)
     3         {
     4             Socket connSocket = o as Socket;
     5 
     6             //通信用的socket连接成功 就可以接收消息了
     7             byte[] buffer = new byte[1024 * 1024 * 5];//5M缓存
     8             while (true)
     9             {
    10                 //count是当前接收的字节个数
    11                 int count = connSocket.Receive(buffer);
    12                 string ip = connSocket.RemoteEndPoint.ToString();
    13                 //判断接收到的字节个数 是0表示客户端关闭了
    14                 if (count > 0)
    15                 {
    16 
    17                     //将字节转换为字符串
    18                     string msg = Encoding.UTF8.GetString(buffer, 0, count);
    19                     ShowMsg(ip + " " + DateTime.Now.ToString() + "
    " + msg);
    20                 }
    21                 else
    22                 {
    23                     //socket没办法发送空消息 如果收到空消息 客户端关闭
    24                     ShowMsg(ip + ":" + "断开连接");
    25                     connSocket.Close();
    26                     break;
    27 
    28                 }
    29 
    30             }
    31 
    32         }
    复制代码

    测试:仍然用telnet命令来测试:telnet 127.0.0.1 50000

         测试结果:多对一,一对一,发送消息正常,关闭客户端,服务端正常显示哪个客户端断开连接。

         服务器端所有代码:

     View Code

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Net;
    using System.Net.Sockets;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    using System.Windows.Forms;

    namespace Wolfy.ChatServer
    {
    public partial class Server : Form
    {
    public Server()
    {
    InitializeComponent();
    //不让其检查跨线程的操作
    Control.CheckForIllegalCrossThreadCalls = false;
    }
    //存放endpoin和通信用的socket
    Dictionary<string, Socket> dic = new Dictionary<string, Socket>();
    private void btnSend_Click(object sender, EventArgs e)
    {
    ServerSendMsg(this.txtInputMsg.Text);
    }
    /// <summary>
    /// 服务器给客户端发送消息
    /// </summary>
    private void ServerSendMsg(string msg)
    {
    //服务器给客户端发消息
    string userkey = comboBoxEndpoint.Text;
    if (!string.IsNullOrEmpty(userkey))
    {
    ShowMsg(msg);
    byte[] buffer = Encoding.UTF8.GetBytes(msg);
    dic[userkey].Send(buffer);
    msg = "";
    }
    else
    {
    MessageBox.Show("请选择客户端");
    }
    }

    private void btnStartService_Click(object sender, EventArgs e)
    {
    //服务器ip地址
    IPAddress ip = IPAddress.Parse(txtIPAddress.Text);
    //ip地址和端口
    IPEndPoint endpoint = new IPEndPoint(ip, int.Parse(txtPort.Text));
    //创建用于监听的socket
    Socket socketListener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    //绑定ip和端口
    socketListener.Bind(endpoint);
    //开始监听 限制连接数 最多可以连接10个
    socketListener.Listen(10);
    ShowMsg("开始监听......");
    //创建线程 去监听连接
    Thread th = new Thread(ListenConn);
    //将线程变为后台线程
    th.IsBackground = true;
    th.Start(socketListener);
    }
    private void ListenConn(object o)
    {
    //将参数o 转化为监听的socket
    Socket socketListener = o as Socket;
    //写入循环 每一个连接就创建一个通信用的socket
    while (true)
    {
    //当有客户端连接成功 创建通信用的socket
    Socket connSocket = socketListener.Accept();
    string ip = connSocket.RemoteEndPoint.ToString();
    ShowMsg(ip + " " + DateTime.Now.ToString() + " 连接成功");
    //连接成功后加入字典
    dic.Add(ip, connSocket);
    comboBoxEndpoint.Items.Add(ip);
    //创建一个新线程去接收消息
    Thread th = new Thread(ReceiveMsg);
    th.Start(connSocket);
    }

    }
    //接收客户端的消息
    private void ReceiveMsg(object o)
    {
    Socket connSocket = o as Socket;

    //通信用的socket连接成功 就可以接收消息了
    byte[] buffer = new byte[1024 * 1024 * 5];//5M缓存
    while (true)
    {
    //count是当前接收的字节个数
    int count = connSocket.Receive(buffer);
    string ip = connSocket.RemoteEndPoint.ToString();
    //判断接收到的字节个数 是0表示客户端关闭了
    if (count > 0)
    {
    //将字节转换为字符串
    string msg = Encoding.UTF8.GetString(buffer, 0, count);
    ShowMsg(ip + " " + DateTime.Now.ToString() + " " + msg);
    }
    else
    {
    //socket没办法发送空消息 如果收到空消息 客户端关闭
    ShowMsg(ip + ":" + "断开连接");
    connSocket.Close();
    break;
    }

    }

    }
    /// <summary>
    /// 提示信息辅助方法
    /// </summary>
    /// <param name="msg"></param>
    private void ShowMsg(string msg)
    {
    this.txtMsgView.AppendText(msg + " ");
    }

    private void txtInputMsg_KeyUp(object sender, KeyEventArgs e)
    {
    //如果用户按下了Enter键
    if (e.KeyCode == Keys.Enter)
    {
    //则调用 服务器向客户端发送信息的方法
    ServerSendMsg(this.txtInputMsg.Text);
    }
    }
    }
    }

    客户端实现

         客户端创建的socket即负责连接又负责通信,所以这里和服务端不同。客户端连接、接收消息和发送消息代码如下:

     View Code

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows.Forms;
    using System.Net.Sockets;
    using System.Net;
    using System.Threading;
    namespace Wolf.ChatClient
    {
    public partial class Client : Form
    {
    public Client()
    {
    InitializeComponent();
    //不让检查跨线程操作
    Control.CheckForIllegalCrossThreadCalls = false;
    }
    Socket socket;
    private void btnStartService_Click(object sender, EventArgs e)
    {
    //连接服务器的ip和端口
    IPAddress ip = IPAddress.Parse(txtIPAddress.Text);
    IPEndPoint endpoint = new IPEndPoint(ip, int.Parse(txtPort.Text));
    //客户端的socket即负责连接又负责通信
    socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    //连接服务器
    socket.Connect(endpoint);
    ShowMsg("连接成功......");
    //和服务器连接成功后就可以接收服务端的消息了
    Thread th = new Thread(ReceiveMsg);
    th.IsBackground = true;
    th.Start();

    }
    private void ReceiveMsg()
    {
    byte[] buffer = new byte[1024 * 1024 * 5];
    while (true)
    {
    int count = socket.Receive(buffer);
    string msg = Encoding.UTF8.GetString(buffer, 0, count);
    ShowMsg(this.txtIPAddress.Text + ":" + this.txtPort.Text + " " + DateTime.Now.ToString() + " " + msg);
    }
    }
    private void ShowMsg(string msg)
    {
    txtMsgView.AppendText(msg + " ");
    }
    private void btnSend_Click(object sender, EventArgs e)
    {
    ClientSendMsg(this.txtInputMsg.Text);
    }

    /// <summary>
    /// 客户端向服务端发送消息
    /// </summary>
    /// <param name="msg"></param>
    private void ClientSendMsg(string msg)
    {
    //向服务端发送消息
    if (socket != null)
    {
    ShowMsg(msg);
    byte[] buffer = Encoding.UTF8.GetBytes(msg);
    socket.Send(buffer);
    msg = "";
    }
    else
    {
    ShowMsg("<<<<请先连接服务器>>>");
    }
    }

    private void txtInputMsg_KeyUp(object sender, KeyEventArgs e)
    {
    //如果用户按下了Enter键
    if (e.KeyCode == Keys.Enter)
    {
    //则调用 服务器向客户端发送信息的方法
    ClientSendMsg(this.txtInputMsg.Text);
    }
    }

    private void Client_FormClosing(object sender, FormClosingEventArgs e)
    {
    //客户端关闭 关闭socket
    socket.Shutdown(SocketShutdown.Both);
    }
    }
    }

    测试结果:


     结语:

           边学习,边动手,实现了两端通信,目前支持一对一,多对一通信功能,代码中针对关闭客户端的情况还有bug,有待进一步修改。

    Alternate Text 作者:Wolfy
    出处:http://www.cnblogs.com/wolf-sun/
    本文以学习、研究和分享为主,欢迎转载,但必须在文章页面明显位置给出原文连接。愿与志同道合的朋友一起成长......
     
    分类: 网络编程
  • 相关阅读:
    Android的数据存储
    Servlet第一天
    JavaScript高级程序设计读书笔记(3)
    Interesting Papers on Face Recognition
    Researchers Study Ear Biometrics
    IIS 发生意外错误 0x8ffe2740
    Father of fractal geometry, Benoit Mandelbrot has passed away
    Computer vision scientist David Mumford wins National Medal of Science
    Pattern Recognition Review Papers
    盒模型bug的解决方法
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3332357.html
Copyright © 2011-2022 走看看