吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 2828|回复: 8
收起左侧

[其他转载] Socket通信

[复制链接]
never_four 发表于 2020-2-28 23:04
本帖最后由 never_four 于 2020-2-28 23:08 编辑

C# ===> WinForm   ====> Socket 通信

一.服务端UI



   



二.客户端UI



   


三.Socket通信在Vs中的整体结构图



   


四.服务端代码

[C#] 纯文本查看 复制代码
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 _001_Server
{
    public partial class FrmServer : Form
    {
        public FrmServer()
        {
            InitializeComponent();
        }

        private void FrmServer_Load(object sender, EventArgs e)
        {
            txtIp.Text = GetLocalIp.IpAddress();
            txtPort.Text = "5000";

            //关闭对文本框的非法线程操作检查
            Control.CheckForIllegalCrossThreadCalls = false;
        }

        private void btnStartServer_Click(object sender, EventArgs e)
        {
            try
            {
                //1.创建监听的Socket
                Socket listenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

                //2.获取当前Ip地址
                IPAddress ip = IPAddress.Parse(txtIp.Text);

                //3.组成IP地址和Port号
                IPEndPoint point = new IPEndPoint(ip, int.Parse(txtPort.Text));

                //4.服务器开始对当前应用程序进行监听 (负责监听的Socket绑定IP地址和端口号)
                listenSocket.Bind(point);

                //5.设置监听队列
                listenSocket.Listen(10);  //监听队列挂起的最大长度

                //6.显示监听成功的信息
                ShowReceiveMsg("监听成功,正在等待客户端的连接......");

                //7.接收客户端发送过来的信息
                //定义线程
                Thread th = new Thread(ReConnClientMsg);

                //将线程设置为后台线程 (防止影响UI线程)
                th.IsBackground = true;

                //传入参数 并启动线程
                th.Start(listenSocket);

            }
            catch { }


        }

        //定义键值对集合 存放连接服务器的客户端的 ip地址 和 Socket 信息
        Dictionary<string, Socket> dicSocketList = new Dictionary<string, Socket>();
        private void ReConnClientMsg(object socketInfo)
        {

            try
            {
                //循环 不停的刷新来自客户端的信息
                while (true)
                {
                    //类型转换
                    Socket listenSocket = socketInfo as Socket;

                    //1.新建负责和客户端建立连接的 Socket
                    Socket reConnClientSocket = listenSocket.Accept();

                    //给键值对集合添加 连接服务器的客户端的 ip 地址 和  Socket 信息
                    dicSocketList.Add(reConnClientSocket.RemoteEndPoint.ToString(), reConnClientSocket);
                    //给下拉选框中添加 连接服务器客户端的 ip 地址 和端口号
                    cmbAddressList.Items.Add(reConnClientSocket.RemoteEndPoint.ToString());


                    //2.显示成功连接客户端的信息
                    ShowReceiveMsg(reConnClientSocket.RemoteEndPoint.ToString() + ": 连接成功!!!");

                    //3.连接成功后开始接收来自客户端的信息

                    Thread th = new Thread(ReClientMsg);   //这里的ReclientMsg 是将  ReClientMsg()方法,当作 参数使用   

                    //将线程设置为后台线程
                    th.IsBackground = true;

                    //启动线程
                    th.Start(reConnClientSocket);
                }
            }
            catch { }

        }

        private void ReClientMsg(object sockInfo)      //使用线程调用方法是 参数必须是Object 类型
        {
            //类型转换
            Socket ReClientMsgInfo = sockInfo as Socket;

            try
            {
                while (true)
                {
                    //1.新建缓冲区
                    byte[] buffer = new byte[1024 * 1024 * 5];

                    //2.将来自客户端的数据放入缓冲区中
                    int byteNums = ReClientMsgInfo.Receive(buffer);
                    //如果接收数据的字节大小为0 则终止在聊天区域显示
                    if (byteNums == 0) return;

                    //3.定义变量,将缓冲区中的数据转换成字符串
                    string msg = Encoding.UTF8.GetString(buffer, 0, byteNums);

                    //4.显示接收到的信息
                    ShowReceiveMsg(ReClientMsgInfo.RemoteEndPoint.ToString() + ": " + msg);
                }
            }
            catch { }

        }

        private void btnSendMsg_Click(object sender, EventArgs e)
        {
            string ip = string.Empty;
            try
            {
                //拿到下拉选框中的IP地址
                ip = cmbAddressList.SelectedItem.ToString();

            }
            catch (Exception)
            {

                MessageBox.Show("请在地址选择要发送信息的对象", "提示:", MessageBoxButtons.OK, MessageBoxIcon.Error);
                #region 三个参数的含义
                //第一个参数是:提示内容
                //第二个参数是:提示框标题
                //的三个参数是:突时框中的错误图标 
                #endregion

                return;
            }

            if (string.IsNullOrEmpty(txtSendMsg.Text.Trim().ToString()))
            {
                MessageBox.Show("消息内容不能为空", "提示:", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            //将待发送的信息转换为字节数组
            byte[] buffer = Encoding.UTF8.GetBytes(txtSendMsg.Text.Trim());

            //给客户端发送消息
            dicSocketList[ip].Send(buffer);

            //在聊天区域显示服务端发送的信息
            ShowSendMsg(txtSendMsg.Text.Trim());

            //给客户端发送一次信息清空一次文本框中的信息
            txtSendMsg.Clear();
        }

 
        #region 显示信息
        public void ShowReceiveMsg(string str)
        {
            txtChatList.AppendText(DateTime.Now.ToString() + "\r\n" + str + "\r\n");
        }
        public void ShowSendMsg(string str)
        {
            txtChatList.AppendText(DateTime.Now.ToString() + "\r\n" + "我: " + str + "\r\n");
        }
        #endregion
    }
}


五.服务端获取本机IP地址代码



[C#] 纯文本查看 复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace _001_Server
{
  public  class GetLocalIp
    {
        public static string IpAddress()
        {
            try
            {
                //1.得到主机名
                string hostName = Dns.GetHostName();
                //2.新建IpHostEntry容器,存放Ip地址
                IPHostEntry hostEntry = Dns.GetHostEntry(hostName);
                //3.从hostEntry容器中得到IPV4地址
                for (int i = 0; i < hostEntry.AddressList.Length; i++)
                {
                    //如果存放IP地址中的某一个成员是IPV4地址则返回这个IP地址
                    if (hostEntry.AddressList[i].AddressFamily==AddressFamily.InterNetwork)
                    {
                        return hostEntry.AddressList[i].ToString();
                    }
                }
            }
            catch (Exception ex)
            {

                return ex.Message;
            }
            return "";
        }

    }
}



六.客户端代码



[C#] 纯文本查看 复制代码
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 _002_Client
{
    public partial class FrmClient : Form
    {
        public FrmClient()
        {
            InitializeComponent();
        }

        
        Socket socket;
        private void btnConnServer_Click(object sender, EventArgs e)
        {
            try
            {  
                //1.新建负责与服务器端通信的Socket 
                socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                #region 三个参数
                //第一个参数是:Ip地址的类型  IPV4
                //第二个参数是:Socket 的类型       Socket 类型有两种  ===> 1. 流式(用于Tcp服务), 2.数据报形式(用于Udp服务)
                //第三个参数式:服务类型 
                #endregion
                
                //2.获取ip地址
                IPAddress ip = IPAddress.Parse(txtIp.Text);

                //3.将Ip地址和Port号 组合在一起
                IPEndPoint point = new IPEndPoint(ip, int.Parse(txtPort.Text));

                //4.将ip地址和port号 放入Socket中 并连接服务器端
                socket.Connect(point);

                //5.提示连接服务器端成功!
                ShowReServerMsg("连接服务器成功!!!", socket);


                //6.接收来自服务器端的信息
                //创建线程    ===> 客户端会不停的刷新 是否有来自服务器端的消息  这样会导致主窗体的UI线程执行耗时操作
                Thread th = new Thread(ReServerMsg);

                //设置线程为后台线程
                th.IsBackground = true;

                //启动线程
                th.Start();
            }
            catch { }

        }

        /// <summary>
        /// 接收来自服务端的信息
        /// </summary>
        private void ReServerMsg()
        {
            try
            {
                while (true)
                {
                    //1.新建缓冲区
                    byte[] buffer = new byte[1024 * 1024 * 5];

                    //2.将来自服务器端的字节类型数组信息放入缓冲区
                    int byteNums = socket.Receive(buffer);
                 
                    if (byteNums == 0) return;

                    //3.将字节数组转换为字符串类型
                    string msg = Encoding.UTF8.GetString(buffer, 0, byteNums);
                    #region 三个参数的意思
                    //第一个参数是:缓冲区中的数据
                    //第二个参数是:从字节类型数组缓冲区的0位开始转换数据
                    //第三个参数是:服务器传入的字节类型数组的实际大小 
                    #endregion

                    //4.在客户端聊天区域显示服务器端发送来的信息
                    ShowReServerMsg(msg, socket);
                }
            }
            catch { }


        }


        private void FrmClient_Load(object sender, EventArgs e)
        {
            //关闭对文本框的非法线程操作检查
            Control.CheckForIllegalCrossThreadCalls = false;
        }

        private void btnSendMsg_Click(object sender, EventArgs e)
        {

            //1.如果消息编辑区域的信息为空则提示,并终止给服务器发送信息
            if (string.IsNullOrEmpty(txtSendMsg.Text.Trim().ToString()))
            {
                MessageBox.Show("消息内容不能为空!", "提示:", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            //2.将发送给服务器端的信息转换为字节数组类型
            byte[] buffer = Encoding.UTF8.GetBytes(txtSendMsg.Text.Trim());

            //3.给服务器端发送消息
            socket.Send(buffer);

            //4.在客户端消息列表中显示给服务器发送的信息
            ShowSendServerMsg(txtSendMsg.Text.ToString());

            //5.给服务端发送一次信息,清除一次消息编辑区域的信息
            txtSendMsg.Clear();

        }

        #region 显示信息

        /// <summary>
        /// 显示接收来自服务器端的信息
        /// </summary>
        /// <param name="str">提示信息</param>
        /// <param name="socketInfo">服务器端的Socket的信息</param>
        private void ShowReServerMsg(string str, Socket socketInfo)
        {
            //SockInfo.RemoteEndPoint.ToString();   获得服务器端的Ip地址和端口号
            //DateTime.Now.ToString();  获取当前时间日期
            txtChatList.AppendText(DateTime.Now.ToString() + "\r\n" + socketInfo.RemoteEndPoint.ToString() + ": " + str + "\r\n");
        }

        /// <summary>
        /// 在客户端信息列表中显示发送给服务器端的信息
        /// </summary>
        /// <param name="str"></param>
        private void ShowSendServerMsg(string str)
        {
            txtChatList.AppendText(DateTime.Now.ToString() + "\r\n" + "我: " + str + "\r\n");
        }
        #endregion
    }
}



七.代码源文件Gitee地址

https://gitee.com/Never_Fours/Socket.git


免费评分

参与人数 1吾爱币 +1 热心值 +1 收起 理由
min_x91 + 1 + 1 谢谢@Thanks!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

 楼主| never_four 发表于 2020-2-28 23:10
注释特别详细,适合学Socket通信的新手哦!!!
游泳的猪 发表于 2020-2-28 23:55
jun57663796 发表于 2020-2-29 00:24
lyswj 发表于 2020-3-1 10:16
学习了,一般都在用封装好的
 楼主| never_four 发表于 2020-3-1 22:13
lyswj 发表于 2020-3-1 10:16
学习了,一般都在用封装好的

万丈高楼,平地起嘛
futing87 发表于 2020-3-2 17:07
代码复制下来学习了
iliulin 发表于 2021-1-28 17:20
地址内容404了
 楼主| never_four 发表于 2021-2-2 09:09

https://gitee.com/Code_Ha/Socket.git
重新补一个地址
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-25 19:45

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表