C# TCP/IP 连接实现数据收发 Demo (Visual Studio)

添加using指令集:

using System.Net.Sockets;
using System.Threading;
using System.Net;

添加定义(IP地址 IP接口 berkeley套接字接口):

private IPAddress serverIP = IPAddress.Parse("127.0.00.1");
private IPEndPoint serverFullAddr;
private Socket sock;

断开连接:

//断开连接
        private void btnClose_Click(object sender, EventArgs e)
        {
            sock.Close();
            btnConn.Enabled = true ;
        }


连接服务器:

//连接服务器端
        private void btnConn_Click(object sender, EventArgs e)
        {
            btnConn.Enabled = false;
            serverIP = IPAddress.Parse(tbxIP.Text);
            try
            {
                serverFullAddr = new IPEndPoint(serverIP, int.Parse(tbxPort.Text));//设置IP,端口
                sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                //指定本地主机地址和端口号
                sock.Connect(serverFullAddr);
                //btnConn.Enabled = false;
                lblError.Text = "连接服务器成功。。。。";
                btnClose.Enabled = true;
                sock.Close();
               
            }
            catch (Exception ee)
            {
                btnConn.Enabled = true;
                lblError.Text = "连接服务器失败。。。请仔细检查服务器是否开启"+ ee;
            }
        }


发送消息:

//发送消息
        private void btnSend_Click(object sender, EventArgs e)
        {
            serverFullAddr = new IPEndPoint(serverIP, int.Parse(tbxPort.Text));//设置IP,端口
            sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            //指定本地主机地址和端口号
            sock.Connect(serverFullAddr);
            byte[] byteSend = System.Text.Encoding.Default.GetBytes(this.tbxMessage.Text);
            byte[] message = new byte[1024];
            string mess = "";
            int bytes = 0;
            try
            {
                //发送数据
                sock.Send(byteSend);
               
                bytes = sock.Receive(message);//接收数据
                mess = mess + Encoding.Default.GetString(message,0,bytes);//编码(当接收的字节大于1024的时候 这应该是循环接收,测试就没有那样写了)
                //do
                //{
                //    bytes = newSocket.Receive(message, message.Length, 0);
                //    mess = mess + Encoding.ASCII.GetString(message, 0, bytes);
                //}
                //while (bytes > 0);
                tbxMessage.Text = mess; 
            }
            catch (Exception ex)
            {
                lblError.Text = "出现错误,请联系管理员"+ex;
            }
            sock.Close();
        }


清空消息:


 //清空消息
        private void btnClean_Click(object sender, EventArgs e)
        {
            tbxMessage.Text = "";
        }


接收数据(由于多线程的原因,稍微麻烦一点):

1.打开线程

Thread myThead = null;

2.线程函数,类似于指定中断服务函数

            myThead = new Thread(new ThreadStart(BeginListen));
            myThead.Start();

3.编写函数(这一部分理解比较麻烦,涉及委托,因为要是用的显示数据的控件是在主线程里面打开的,而控件的缺省值是不可以跨线程使用,所以需要委托。)

a.需要好好理解Invoke函数:他是在拥有该控件的基础窗口句柄的线程上,用指定的参数列表执行指定的委托。通俗一点就是,我委托拥有这个控件的线程来帮我执行这个操作。

b.为什么使用accept函数。为了新的连接创造一个新的socket呢?理解为:sock这个socket已经在监听了,而且队列中允许的传入连接数有多个,所以新创建一个socket,当队列中有忙碌的传入连接时,将地址给新的socket来recieve数据。高效,稳定一些。


        private void BeginListen()
        {
            serverI2.xianP = IPAddress.Parse(tbxIP.Text);   //IP
            serverFullAddr = new IPEndPoint(serverIP, int.Parse(tbxPort.Text));//设置IP,端口
            sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            //指定本地主机地址和端口号
            sock.Bind(serverFullAddr);
            lbxMessage.Invoke(new SetTextCallback(SetText), "启动成功 时间:" + DateTime.Now, 1);
            byte[] message = new byte[1024];
            string mess = "";
            while (true)
            {
                try
                {
                    sock.Listen(5);//backlog 参数指定队列中最多可容纳的等待接受的传入连接数。
                    Socket newSocket = sock.Accept();//为新建连接创建新的socket。sock这个socket是用来监听的,当他有连接请求的时候,将地址给新的socket来接收,这样不影响他继续监听原本的socket。
                    int bytes = newSocket.Receive(message);//用刚才chuangjian接收数据
                    mess = Encoding.Default.GetString(message, 0, bytes);//对接收字节编码(S与C 两端编码格式必须一致不然中文乱码)(当接收的字节大于1024的时候 这应该是循环接收,测试就没有那样写了)

                    lbxMessage.Invoke(new SetTextCallback(SetText), mess, 1);//子线程操作主线程UI控件

                    //获取客户端的IP和端口
                    string ip11 = newSocket.RemoteEndPoint.AddressFamily.ToString();
                    
                    mess = "已接收数据: "+ mess +" 来自:" +ip11+ " 当前时间为:" + DateTime.Now; //处理数据
                    newSocket.Send(Encoding.Default.GetBytes(mess));//向客户端发送数据

                }
                catch (SocketException se)
                {
                    lbxMessage.Invoke(new SetTextCallback(SetText), mess + se, 1);

                }
            }
        }


        #region//声名委托
        //生命delegate对象,可以理解成函数指针
        delegate void SetTextCallback(string text, int num);
        //欲传递的方法,她与CompareDelegate具有相同的参数和返回值类型
        private void SetText(string text, int num)
        {
            lbxMessage.Items.Add(text);
        }
        #endregion



一个参考的完整的Demo:

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;
using System.Net.Sockets;
using System.IO;
using System.Threading;
 
namespace TcpClientTest
{
    public partial class FormMain : Form
    {
        public FormMain()
        {
            InitializeComponent();
        }
 
        private void FormMain_Load(object sender, EventArgs e)
        {
            //初始化控件
            txtSendMssg.Text = "测试数据";
 
            //打开Listener开始监听
            Thread thrListener = new Thread(new ThreadStart(Listen));
            thrListener.Start();
        }
 
        private void FormMain_FormClosing(object sender, FormClosingEventArgs e)
        {
            //强制关闭程序(强行终止Listener)
            Environment.Exit(0);
        }
 
        //发送数据
        private void btnSend_Click(object sender, EventArgs e)
        {
            TcpClient tcpClient = new TcpClient();
            //tcpClient.Connect(IPAddress.Parse("170.0.0.78"), 2014);
            tcpClient.Connect(IPAddress.Parse("127.0.0.1"), 2014);
 
            NetworkStream ntwStream = tcpClient.GetStream();
            if (ntwStream.CanWrite)
            {
                Byte[] bytSend = Encoding.UTF8.GetBytes(txtSendMssg.Text);
                ntwStream.Write(bytSend, 0, bytSend.Length);
            }
            else
            {
                MessageBox.Show("无法写入数据流");
 
                ntwStream.Close();
                tcpClient.Close();
 
                return;
            }
 
            ntwStream.Close();
            tcpClient.Close();
        }
 
        //监听数据
        private void Listen()
        {
            Socket listener = new Socket(AddressFamily.InterNetwork, 
                SocketType.Stream, ProtocolType.Tcp);
            listener.Bind(new IPEndPoint(IPAddress.Any, 2014));
 
            //不断监听端口
            while (true)
            {
                listener.Listen(0);
                Socket socket = listener.Accept();
                NetworkStream ntwStream = new NetworkStream(socket);
                StreamReader strmReader = new StreamReader(ntwStream);
                Invoke(new PrintRecvMssgDelegate(PrintRecvMssg), 
                    new object[] { strmReader.ReadToEnd() });
                socket.Close();
            }
 
            //程序的listener一直不关闭
            //listener.Close();
        }
 
        //线程内向文本框txtRecvMssg中添加字符串及委托
        private delegate void PrintRecvMssgDelegate(string s);
        private void PrintRecvMssg(string info)
        {
            txtRecvMssg.Text += string.Format("[{0}]:{1}\r\n", 
                DateTime.Now.ToLongTimeString(), info);
        }
    }
}


  • 22
    点赞
  • 115
    收藏
    觉得还不错? 一键收藏
  • 13
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值