zoukankan      html  css  js  c++  java
  • 简单的C#TCP协议收发数据示例

    参考:http://www.cnblogs.com/jzxx/p/5630516.html

    一、原作者的这段话很好,先引用一下:

    Socket的Send方法,并非大家想象中的从一个端口发送消息到另一个端口,它仅仅是拷贝数据到基础系统的发送缓冲区,然后由基础系统将发送缓冲区的数据到连接的另一端口。值得一说的是,这里的拷贝数据与异步发送消息的拷贝是不一样的,同步发送的拷贝,是直接拷贝数据到基础系统缓冲区,拷贝完成后返回,在拷贝的过程中,执行线程会IO等待, 此种拷贝与Socket自带的Buffer空间无关,但异步发送消息的拷贝,是将Socket自带的Buffer空间内的所有数据,拷贝到基础系统发送缓冲区,并立即返回,执行线程无需IO等待,所以异步发送在发送前必须执行SetBuffer方法,拷贝完成后,会触发你自定义回调函数ProcessSend,在ProcessSend方法中,调用SetBuffer方法,重新初始化Buffer空间。

    二、代码如下:

    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}
    ", 
                    DateTime.Now.ToLongTimeString(), info);
            }
        }
    }

    需要在项目上加两个TextBox名字分别为 txtSendMssg、txtRecvMssg和一个Button(名字为 btnSend

    三、运行效果(效果图片见原作者文章)

    在发送数据的文本框中分别输入“千山鸟飞绝”、“万径人踪灭”、“孤舟蓑笠翁”、“独钓寒江雪”四句话,输完一句话,单击一次“发送数据”按钮,就可以在接收数据里看到这四句话了。上面代码中,信息的发送时通过TcpClient连接到127.0.0.1的2014端口,信息的接收是通过Listen函数不断监听本机的2014端口实现的。从自己创建的线程中修改控件信息,用到了委托。

    四、补充

    1、运行时提示:由于目标计算机积极拒绝,无法连接。 127.0.0.1:2014

    用 System.Net.Dns.GetHostAddresses("localhost")[1].ToString(); 取得的也是127.0.0.1

    参考:https://blog.csdn.net/u010784236/article/details/51820284 也与我的情况不一样。

    想想我是在局域网中,用ipconfig /all 找到自己的ip  192.168.3.5 替换  127.0.0.1 添加防火墙规则,仍不行。关闭防火墙,还不行。

    (如何获得IP,还可参考:https://blog.csdn.net/fwj380891124/article/details/18214145)

    正准备放弃时,看到 https://blog.csdn.net/fengzheng22/article/details/17266105 其中有一句:

    需要你用tcpclient访问的IP的端口正在被监听,否则就会显示积极拒绝,不是看他是否被占用,要看他是否在监听

    想想我是直接整体复制的代码,不是双击窗体后单独写的formMain_load代码。而服务端应该是在formMain_load时开始监听。

    于是重新修改代码,使得formMain_load时先运行服务端监听的代码。重新生成并运行,正常。这个错误太低级。

    如果在局域网两台电脑上分别运行客户端和服务端,要确保能ping通,检查防火墙规则。参考这里:https://jingyan.baidu.com/article/a65957f4f557cb24e67f9ba6.html

    2、另外,这里还有个例子:https://www.jb51.net/article/130148.htm

    3、参考:https://www.cnblogs.com/straight/articles/7660889.html

    socket起源于Unix,而Unix/Linux基本哲学之一就是“一切皆文件”,都可以用“打开open –> 读写write/read –> 关闭close”模式来操作。我的理解就是Socket就是该模式的一个实现,socket即是一种特殊的文件,一些socket函数就是对其进行的操作(读/写IO、打开、关闭)。 

    如果作为一个服务器,在调用socket()、bind()之后就会调用listen()来监听这个socket,如果客户端这时调用connect()发出连接请求,服务器端就会接收到这个请求。

     isten函数的第一个参数即为要监听的socket描述字,第二个参数为相应socket可以排队的最大连接个数。socket()函数创建的socket默认是一个主动类型的,listen函数将socket变为被动类型的,等待客户的连接请求。

    TCP服务器端依次调用socket()、bind()、listen()之后,就会监听指定的socket地址了。TCP客户端依次调用socket()、connect()之后就向TCP服务器发送了一个连接请求。TCP服务器监听到这个请求之后,就会调用accept()函数取接收请求,这样连接就建立好了。之后就可以开始网络I/O操作了,即类同于普通文件的读写I/O操作。

     4、TCP协议三次握手过程分析 参考:http://www.cnblogs.com/rootq/articles/1377355.html

    5、C# TCP多线程服务器示例 参考:https://www.cnblogs.com/zhangxiaoyong/p/6486311.html

    6. C# socket端口复用-多主机头绑定 参考:https://www.cnblogs.com/viewcozy/p/4666137.html

    7、定时执行、一对多  参考:  http://www.cnblogs.com/chenxizhang/archive/2011/09/10/2172994.html

    8、在同步模式中,在服务器上使用Accept方法接入连接请求,而在客户端则使用Connect方法来连接服务器。相对地,在异步模式下,服务器可以使用BeginAccept方法和EndAccept方法来完成连接到客户端的任务,在客户端则通过BeginConnect方法和EndConnect方法来实现与服务器的连接。  参考:http://www.cnblogs.com/sunev/archive/2012/08/07/2625688.html

    9、C#的IPAddress IPEndPoint  参考 https://www.cnblogs.com/2Yous/p/5797592.html

  • 相关阅读:
    poj 3243 Clever Y(BabyStep GiantStep)
    poj 2417 Discrete Logging
    poj 3481 Double Queue
    hdu 4046 Panda
    hdu 2896 病毒侵袭
    poj 1442 Black Box
    hdu 2815 Mod Tree
    hdu 3065 病毒侵袭持续中
    hdu 1576 A/B
    所有控件
  • 原文地址:https://www.cnblogs.com/pu369/p/9987027.html
Copyright © 2011-2022 走看看