C#:简单的Socket异步通信功能(客户端)

61 篇文章 1 订阅
17 篇文章 0 订阅

上一篇(http://www.rexcao.net/archives/159)讲了服务端使用Socket发送消息的方法,这一篇来解决一下客户端如何接收服务端消息的问题。

目标

1、异步接收服务端消息并显示

2、发送自定义消息给服务端(由于上一篇做的是Windows服务,没有界面,这个需要另行处理才可以显示客户端的消息)

思路

1、异步从一个已连接的Socket对象中获取消息

2、在按钮的点击事件中向服务端发送消息

注意事项

1、因为使用的是异步通信,回调方法是由系统执行的,这个牵扯到跨进程调用资源的问题

2、一旦一个Socket连接断开后,再次建立连接需要创建一个新的Socket对象来与服务端建立连接。

代码

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;


namespace FormClient
{
    public partial class Form1 : Form
    {
        private delegate void FlushClient(string msg);//使用委托解决跨线程调用问题
        private delegate void DelegateControls(bool val, string msg);
        Socket socket;
        static string host = "127.0.0.1";
        static int port = 4530;
        static byte[] buffer = new byte[1024];
        public Form1()
        {
            InitializeComponent();
        }


        private void Form1_Load(object sender, EventArgs e)
        {
            this.ConServer();
        }


        private void btnRetry_Click(object sender, EventArgs e)
        {
            this.ConServer();
        }
        /// <summary>
        /// 向textbox写入信息并使其滚动至底部
        /// 支持跨线程调用(使用委托实现,参考:http://bbs.csdn.net/topics/280001358 )
        /// </summary>
        /// <param name="msg">要显示的消息文本</param>
        private void WriteScroll(string msg)
        {
            if (this.InvokeRequired)
            {
                FlushClient fc = new FlushClient(WriteScroll);
                object[] ps = new object[] { msg };
                this.Invoke(fc, ps);
                return;
            }
            else
            {
                msg = msg + "\r\n";
                textBox1.Text += msg;
                textBox1.Focus();
                textBox1.Select(textBox1.TextLength, 0);
                textBox1.ScrollToCaret();
            }
        }
        /// <summary>
        /// 连接服务器
        /// </summary>
        private void ConServer()
        {
            this.WriteScroll("Trying to connect the server...");
            try
            {
                this.socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                this.socket.Connect(host, port);
                this.socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveMessage), this.socket);
                ControlsSwitch(false, "");
            }
            catch (SocketException ex)
            {
                this.ControlsSwitch(true, ex.Message);
            }
            catch (Exception ex)
            {
                this.WriteScroll(ex.Message);
            }
        }
        /// <summary>
        /// 接收来自服务器的消息
        /// </summary>
        /// <param name="ar"></param>
        public void ReceiveMessage(IAsyncResult ar)
        {
            try
            {
                var socket = ar.AsyncState as Socket;


                var length = socket.EndReceive(ar);
                //读取出来消息内容
                var message = Encoding.Unicode.GetString(buffer, 0, length);
                //显示消息
                this.WriteScroll("From host:" + message);


                socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveMessage), socket);
            }
            catch (SocketException ex)
            {
                ControlsSwitch(true, ex.Message);
            }
            catch (InvalidOperationException ex)
            {
                ControlsSwitch(true, ex.Message);
            }


        }




        private void ControlsSwitch(bool val, string msg)
        {
            if (this.InvokeRequired)
            {
                DelegateControls dc = new DelegateControls(ControlsSwitch);
                object[] ps = new object[] { val, msg };
                this.Invoke(dc, ps);
            }
            else 
            {
                btnRetry.Visible = val;
                lblStatus.Text = msg;
            }
        }


        /// <summary>
        /// 任何时候想要WriteScroll时,都调用这个方法,而不是直接调用WriteScroll
        /// 这个方法可以根据你的调用是否跨线程而进行相应的处理
        /// </summary>
        /// <param name="msg"></param>
        public void InDirectOutput(string msg)
        {
            if (this.InvokeRequired)//根据这个来判断是否跨线程
            {
                //是跨线程,则用Invoke的方式,在创建的线程内执行
                FlushClient fc = new FlushClient(WriteScroll);
                //这里初始化参数并传入Invoke函数。
                object[] ps = new object[] { msg };
                this.Invoke(fc, ps);
                return;
            }
            else 
            {
                //不是跨线程,直接访问
                WriteScroll(msg);
            }
        }


        private void btnSend_Click(object sender, EventArgs e)
        {
            var outputBuffer = Encoding.Unicode.GetBytes(txtSend.Text);
            this.socket.BeginSend(outputBuffer, 0, outputBuffer.Length, SocketFlags.None, null, null);
        }
    }
}

最终结果

test

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值