• 通信编程2中等难度Socket实用篇(转载)



    同一个东西---Socket。这个有点难度,为了提高程序的趣味性,我想起个过年前看到的例子----有点类似QQ的东西,不过只能2个人
    互相聊天,而且有建的有局域网的朋友更是值得一试。本篇难度一般,在下虽然现职教师,自认讲东西能力差,我会尽我最大的努力
    去讲解以下的例子
    本例分服务器端程序和客户端程序,对于服务器端,要用到以下内容:
    1 TcpListener 建立一个服务器监听
    TcpListener len=new TcpListener(port);
    其参数是端口号,段口号用来标识程序。这样说吧,很多人玩过MU私服或者传奇私服吗?还记得以前MU私服没有登陆器的时候要改端口号
    为44405吗??44405这个号就表明了MU这个游戏,正应为有这种标识记号,当你运行MU私服客户端的时候,不会连接到传奇的服务器上去
    2 开始监听
    len.Start();
    3挂起连接请求
    Socket s=len.AcceptSocket ();
    这个AcceptSocket ()成功的话,就返回一个套接字类型的东西
    4建立工作通道
    NetWorkStream ns=new NetworkStream (s);在此套接字上建立ns通道,注意ns是NetWorkStream类型的
    对于客户端,要用到以下的东西
    1 TcpClient 用法如下
    TcpClient cli=new TcpClient();也就是实例化一个叫cli的TcpClient 注意的是必须实例化
    2 Connect(终点,端口号);
    建立了TcpClient后,要把他连接“绑定”到其对应的端口比如如果在服务器端的IP是192.168.0.4,port是4500的话
    1建立IPAddress
    IPAddress ip=IPAddress.Parse ("192.168.0.4");
    2把它作为参数
    cil.Connect(ip,4500);这个连接,是与我们将要做的服务器程序的连接
    要注意2点,第1,要在以有的实例上建立连接,这里已有的是cil第2,很多程序号已经占用了端口号,比如我这里说的4500,可能你的
    计算机上有别的程序是这个号,而同一个号不能在2个程序里用,你就要换个号,你也许说:我不知道哪些号已经被占用。是这样的,第1
    1024号以前的最好别用,应为很多是系统程序用的,第2,如果4500号别的程序已经用了,你在调试完了,应用程序的时候,系统要提示你
    说“一般,一个端口号只能用一次”,你遇到这样的提示再把号改过就是。
    3闭合通道
    刚才建立了个服务器端的通道,ns,但是这个通道是不闭合的,ns的终点在那里?没有指定
    NetWorkStream output=cle.GetStream();
    GetStream原意思是“得到流”,进一步来说,得到什么流?再看一下cle.GetStream(),我们知道了是从cle得到的,而cle又通过cle.Connect
    和服务器连接,所以我们得到的结论是cle.GetStream()得到的流(我理解成“得到的通道”)
    既然在前面建立了个通道ns,现在通过客户端的“得到通道”,那么现在工作通道就闭和了,你也许要问这个闭和通道的作用,呵呵
    你可以回忆一下FileStream作用是什么,也大致知道这个NetWorkStream的作用了把。


    好了,最后还要说下这个东西System.IO .BinaryWriter 用于向指定通道写操作,当然也有System.IO .BinaryReader哦
    还要回顾一下这个东西System.Threading 能弄出多线程的东西。应为一般来说,一个窗体在Main()里运行的是什么?是Application.Run(new Form());
    对,是窗体,但是在窗体背后的服务器也在运行啊,这是个双重运行的程序(前台窗体操作,后台服务器运行操作)其实很多稍微大型点的程序都是多线程的
    比如你按下Windows任务管理器,在进程栏看到的所有进程,就是现在你机子上的多个线程。



    好了,现在开始编写程序,本来想画几个图帮助理解,由于只能上传15K的内容。图只好省略了
    1先制作服务器端
    服务器端和客户端都由一个窗体 ,2个richtextbox,一个按牛组成2个richtextbox分别是inrichtextbox和derichtextbox,比如在inrichtextbox输入文字
    “你好”在服务器端和客户端的derichtextbox都会显示Server>>“你好”,同样,在客户端的inrichtextbox输入“你也好”,在服务器端和客户端的derichtextbox
    都会显示Client>>“你也好”,代码如下
    using System;
    using System.Drawing;
    using System.Collections;
    using System.ComponentModel;
    using System.Windows.Forms;
    using System.Data;
    using System.Net.Sockets ;
    using System.Net ;
    using System.IO ;
    using System.Threading ;


    namespace 网络通信2A
    {
    /// <summary>
    /// Form1 的摘要说明。
    /// </summary>
    public class Server : System.Windows.Forms.Form
    {
    private System.Windows.Forms.RichTextBox dirichTextBox1;
    private System.Windows.Forms.RichTextBox inrichTextBox2;
    private System.Windows.Forms.Button button1;
    private System.Net .Sockets .NetworkStream ns;
    private System.Threading .Thread th;
    private Socket s;
    private System.IO .BinaryReader re;
    private System.IO .BinaryWriter wr;
    private string rong;
    /// <summary>
    /// 必需的设计器变量。
    /// </summary>
    private System.ComponentModel.Container components = null;


    public Server()
    {
    //
    // Windows 窗体设计器支持所必需的
    //
    InitializeComponent();
    th=new Thread (new ThreadStart (RunServer));
    th.Start ();


    //
    // TOD 在 InitializeComponent 调用后添加任何构造函数代码
    //
    }


    /// <summary>
    /// 清理所有正在使用的资源。
    /// </summary>
    protected override void Dispose( bool disposing )
    {
    if( disposing )
    {
    if (components != null)
    {
    components.Dispose();
    }
    }
    base.Dispose( disposing );
    }


    #region Windows 窗体设计器生成的代码
    /// <summary>
    /// 设计器支持所需的方法 - 不要使用代码编辑器修改
    /// 此方法的内容。

    #endregion


    /// <summary>
    /// 应用程序的主入口点。
    /// </summary>
    [STAThread]
    static void Main()
    {
    Application.Run(new Server());
    }


    private void button1_Click(o b j e c t sender, System.EventArgs e)
    {
    if(s!=null)
    wr.Write ("Server>>"+this.inrichTextBox2 .Text );
    this.dirichTextBox1 .Text +="\r\nServer>>"+this.inrichTextBox2 .Text ;
    if(this.inrichTextBox2 .Text =="ClE")
    s.Close ();
    this.inrichTextBox2 .Clear ();


    }
    public void RunServer()
    {
    try
    {
    TcpListener len=new TcpListener (4700);//创建监听
    len.Start ();//开始监听
    while(true)//用无限循环,无限通过基于套接字的ns流传信息
    {
    this.dirichTextBox1 .Text ="等待,没连接通哦!";
    s=len.AcceptSocket ();//创建一个套接字,挂起连接请求
    ns=new NetworkStream (s);//在此套接字上建立ns通道
    wr=new BinaryWriter (ns);//wr用来为此通道的写服务
    re=new BinaryReader (ns);//re为此通道的读服务
    /*值得注意的是,wr和re和能与4700断口的程序对接,wr只能向对接的程序写,re只能向对接的读,这和FlieStream中的读写不同了,FileStream建立读写要定义个本机的位置,是死的位置,而这里wr和re对应的位置完全依赖ns和什么程序接通形成完整闭合通道*/
    this.dirichTextBox1 .Text +="现在接通了,呵呵:)";

    do
    {
    try
    {
    rong=re.ReadString ();
    this.dirichTextBox1 .Text +="\r\n"+rong;
    }
    catch(Exception)
    { break; }
    }while(rong!="Clent>>>CLE");
    wr.Close ();re.Close ();ns.Close ();s.Close ();



    }





    }
    catch(Exception err)
    {
    MessageBox.Show (err.Message );}
    }


    private void Server_Closing(o b j e c t sender, System.ComponentModel.CancelEventArgs e)
    {
    System.Environment.Exit (System.Environment .ExitCode );
    }
    }
    }



    2客户缎
    using System;
    using System.Drawing;
    using System.Collections;
    using System.ComponentModel;
    using System.Windows.Forms;
    using System.Data;
    using System.Net ;
    using System.Net .Sockets ;
    using System.IO ;
    using System.Threading ;


    namespace 网络通信2B
    {
    /// <summary>
    /// Form1 的摘要说明。
    /// </summary>
    public class Client : System.Windows.Forms.Form
    {
    private System.Windows.Forms.RichTextBox inrichTextBox1;
    private System.Windows.Forms.RichTextBox dirichTextBox2;
    private System.Windows.Forms.Button button1;
    private System.Windows.Forms.Button button2;
    private Thread th;
    private System.IO .BinaryWriter wr;
    private System.IO .BinaryReader re;
    private string mess;
    private System.Net .Sockets .NetworkStream output;
    /// <summary>
    /// 必需的设计器变量。
    /// </summary>
    private System.ComponentModel.Container components = null;


    public Client()
    {
    //
    // Windows 窗体设计器支持所必需的
    //
    InitializeComponent();
    th=new Thread (new ThreadStart (RunClient));
    th.Start ();
    // TOD 在 InitializeComponent 调用后添加任何构造函数代码
    //
    }


    /// <summary>
    /// 清理所有正在使用的资源。
    /// </summary>
    protected override void Dispose( bool disposing )
    {
    if( disposing )
    {
    if (components != null)
    {
    components.Dispose();
    }
    }
    base.Dispose( disposing );
    }


    #region Windows 窗体设计器生成的代码
    /// <summary>
    /// 设计器支持所需的方法 - 不要使用代码编辑器修改
    /// 此方法的内容。
    /// </summary>
    // button1
    //
    this.button1.Location = new System.Drawing.Point(32, 176);
    this.button1.Name = "button1";
    this.button1.Size = new System.Drawing.Size(59, 23);
    this.button1.TabIndex = 2;
    this.button1.Text = "button1";
    //
    // button2
    //
    this.button2.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
    this.button2.Location = new System.Drawing.Point(280, 176);
    this.button2.Name = "button2";
    this.button2.Size = new System.Drawing.Size(59, 23);
    this.button2.TabIndex = 3;
    this.button2.Text = "发送";
    this.button2.Click += new System.EventHandler(this.button2_Click);
    //
    // Client
    //
    this.AutoScaleBaseSize = new System.Drawing.Size(6, 14);
    this.ClientSize = new System.Drawing.Size(392, 349);
    this.Controls.Add(this.button2);
    this.Controls.Add(this.button1);
    this.Controls.Add(this.dirichTextBox2);
    this.Controls.Add(this.inrichTextBox1);
    this.Name = "Client";
    this.Text = "Client";
    this.Closing += new System.ComponentModel.CancelEventHandler(this.Client_Closing);
    this.ResumeLayout(false);


    }
    #endregion


    /// <summary>
    /// 应用程序的主入口点。
    /// </summary>
    [STAThread]
    static void Main()
    {
    Application.Run(new Client());
    }


    private void button2_Click(o b j e c t sender, System.EventArgs e)
    {
    wr.Write ("Client>>>"+this.inrichTextBox1 .Text );
    this.dirichTextBox2 .Text +="\r\nClient>>>"+this.inrichTextBox1 .Text ;
    this.inrichTextBox1 .Clear ();
    }
    public void RunClient()
    {

    TcpClient cle;
    try
    {
    this.dirichTextBox2 .Text +="客户端立即开始........";


    cle=new TcpClient ();
    file://IPAddress ip=IPAddress.Parse ("192.168.0.33");//与服务器连接
    cle.Connect ("localhost",4700);
    output=cle.GetStream();//与服务器的通道联通,现在通道闭合了
    wr=new BinaryWriter(output);//通过此通道进行读写操作
    re=new BinaryReader(output);
    do
    {
    try
    {
    mess=re.ReadString ();//通过此通道的“读”设备读取服务器传递的信息,显示在“输出”文本筐里.
    this.dirichTextBox2 .Text +="\r\n"+mess;
    }
    catch(Exception)
    { System.Environment .Exit(1); }
    }
    while(mess!="Server>>CLE");
    this.dirichTextBox2 .Text +="\r\n关闭了哈~";
    wr.Close ();re.Close ();output.Close ();cle.Close ();
    Application.Exit();
    }
    catch(Exception err){MessageBox.Show (err.Message );}
    }


    private void Client_Closing(o b j e c t sender, System.ComponentModel.CancelEventArgs e)
    {
    System.Environment.Exit (System.Environment .ExitCode );
    }
    }
    }


    这样就能实现2个窗体的互相通信,窗体关闭的private void Client_Closing(o b j e c t sender, System.ComponentModel.CancelEventArgs e)必不可少,要不染你关闭了窗体 ,但是第2个线程依然在运行,这种情况就只能用
    Windows任务管理器来结束进程了。


    好了,我流下个问题让大家思考。现在比如有4台机子,我怎么让4个客户端程序之间1对1的通信??又怎么让他们集体通信?
    提示:点播与广播,原理如下,大家最好别马上看,先自己想想



    有4台机子,就要做4个客户端(比如叫A.B.C.D)和1个服务器端,4个客户端都cli.Connect()到这个服务器端,应此有4个output=cle.GetStream();
    他们比如为ooutput1=cle1.GetStream();utput2=cle2.GetStream();output3=cle3.GetStream();output4=cle4.GetStream();就是说要建立4个通道
    A和B要通信,A先和服务器通信,服务器得到A信息再同过服务器与B的通道发送给B

  • 相关阅读:
    ios 常见性能优化
    ios Standard Framework和Umbrella Framework
    lua 中容易忘记的细节
    python md5
    lua table 排序
    centos 图形模式与命令行模式设置
    python 中关于 json 的一些相关操作
    python3 入门基础
    lua 函数
    sublime 自定义配置python开发环境
  • 原文地址:https://www.cnblogs.com/chorrysky/p/697816.html
Copyright © 2020-2023  润新知