zoukankan      html  css  js  c++  java
  • C#.NET 比较好用的tcp通信模板(服务器端篇)


    二话不说,大家先看一下我服务端添加的引用

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.IO;
    using System.Linq;
    using System.Net;
    using System.Net.Sockets;
    using System.Runtime.Serialization.Formatters.Binary;
    using System.Text;
    using System.Threading;
    using System.Windows.Forms;
    using commands;

    
    注意一下,这里的最后一个引用commands,与客户端的commands必须是同一个dll,同样的代码编译出来的文件都不行。这是为什么

    捏。试想一下,你用一个规则去序列化一个对象,然后用另一个规则进行反序列化,得到的对象不会是原来的对象了吧。


    好,下一步。这里是服务器端,每一个客户端连到服务器,都对应一个类的对象,然后把它们搞到一个列表里面。这样就方便进行操作了。在这个基础上,给客户端

    发信息,或者转发一个客户端的信息给另一个或多个客户端,都是小case了。

    下面就是客户端对应的类了。

    public class InConnectUser
    {
    public TcpClient client { get; set; }
    public BinaryReader br { get; set; }
    public BinaryWriter bw { get; set; }

    public Guid InUseID { get; set; }
    public bool IfUserLogin=false;

    public Entity.FeeRules obj_enFeeRules = new Entity.FeeRules();
    public Entity.InUse obj_enInUse = new Entity.InUse();
    public Entity.Computer obj_enComputer = new Entity.Computer();
    public Entity.User obj_enUser = new Entity.User();

    public InConnectUser(TcpClient client)
    {
    this.client = client;
    NetworkStream networkstream
    = client.GetStream();
    br
    = new BinaryReader(networkstream);
    bw
    = new BinaryWriter(networkstream);
    }
    public void Close()
    {
    br.Close();
    bw.Close();
    client.Close();
    }
    }

    

    我这里是和网吧管理相关的,所以加了很多逻辑方面的东西在里面就不贴出来占篇幅了。大家如果把代码copy过去发现出错,就注释掉吧。

    话不多,看到关键的地方都写在下面的注释里面。

    

    //在线用户列表
    private List<TcpHelper.InConnectUser> onlineUserList = new List<TcpHelper.InConnectUser>();
    IPAddress localAddress;
    private const int port = 51888;
    private TcpListener myListener;

    //开启服务器的按钮
    private void button_StartServer_Click(object sender, EventArgs e)
    {
    myListener
    = new TcpListener(localAddress, port);
    myListener.Start();
    label_status.Text
    = "开启";

    Thread myThread
    = new Thread(ListenClientConnect);
    myThread.Start();
    //timer1.Enabled = true;
    button_StartServer.Visible = false;
    button_StopServer.Visible
    = true;
    }
    //关闭服务器的按钮
    private void button_StopServer_Click(object sender, EventArgs e)
    {
    label_status.Text
    = "关闭";
    //关闭服务器,移除list的用户。
    //for (int i = onlineUserList.Count - 1; i >= 0; i--)
    //{
    // RemoveOnlineUser(onlineUserList[i]);
    //}
    myListener.Stop();
    button_StartServer.Visible
    = true;
    button_StopServer.Visible
    = false;
    }

    /// <summary>
    /// 监听连接
    /// </summary>
    private void ListenClientConnect()
    {
    TcpClient newClient
    = null;
    while (true)
    {
    try
    {
    //停在此处监听连接,如果有新客户端连接就运行下去
    newClient = myListener.AcceptTcpClient();
    }
    catch (Exception)
    {

    break;
    }
    InConnectUser user
    = new InConnectUser(newClient);
    Thread threadReceive
    = new Thread(ReceiveData);
    threadReceive.Start(user);
    onlineUserList.Add(user);

    }

    }



    /// <summary>
    /// 收消息
    /// </summary>
    /// <param name="UserState"></param>
    private void ReceiveData(object UserState)
    {
    InConnectUser user
    = (InConnectUser)UserState;
    TcpClient client
    = user.client;
    MessageInfo receiveObject;

    while (true)
    {
    try
    {
    byte[] bytes = new byte[999];
    //停在此处,networkstream流中有新数据则读出
    int i = user.br.Read(bytes, 0, 999);
    MemoryStream memory
    = new MemoryStream(bytes);
    BinaryFormatter format
    = new BinaryFormatter();
    receiveObject
    = (MessageInfo)format.Deserialize(memory);
    }
    catch (Exception)
    {
    return;
    }
    switch (receiveObject.CommandsTypes)
    {
    case CommandsTypes.RequestHowLong:
    //这里是我处理各种命令的方法,和这个博客的主题无关,就不贴出来了。
    //处理好之后,就在这个方法里面发送回应给对应的客户端,所以一定要有参数user
    // ManagerHowLong(user);
    break;
    case CommandsTypes.RequestUserLogin:
    // ManagerUserLogin(user, receiveObject);
    break;
    case CommandsTypes.RequestUserlogout:
    // ManagerUserLogout(user);
    break;
    case CommandsTypes.RequestLogout:
    //注意这里是return,本意是如果客户端的连接要关闭, 就用跳出循环
    //但是我的是网吧管理,不考虑这种情况,所以就未做处理
    return;
    case CommandsTypes.RequestModPWD:
    // ManagerModPWD(user, receiveObject);
    break;
    case CommandsTypes.RequestMachineLogin:
    // ManagerMachineLogin(user, receiveObject);
    break;

    case CommandsTypes.RequestTalk:
    // ManagerTalk(receiveObject);
    break;

    default:
    break;
    }

    }

    }

    /// <summary>
    /// 发消息
    /// </summary>
    /// <param name="user">发给谁</param>
    /// <param name="userSend">发送内容</param>
    private void SendToClient(TcpHelper.InConnectUser user, MessageInfo userSend)
    {
    try
    {
    MemoryStream memory
    = new MemoryStream();
    BinaryFormatter format
    = new BinaryFormatter();
    format.Serialize(memory, userSend);
    byte[] bytes = memory.ToArray();

    user.bw.Write(bytes);
    user.bw.Flush();

    }
    catch (Exception)
    {
    //发送失败
    }
    }

    代码不多,但是也要花点小时间去看看条理才会清晰。

    龙弟弟奉献,转载请注明出处谢谢。

    另外我这里有根据这个做成的小聊天程序,大家如果有需要可以找我。

    https://files.cnblogs.com/salty/tcp.rar

    
  • 相关阅读:
    JQuery 简单实现折叠菜单
    机械迷城攻略2
    ffmpeg视频转换及截图
    机械迷城攻略3
    SQL:清空数据库所有数据
    .net发送邮件outlook中文乱码
    我读我的Book
    转:精妙SQL语句收集
    SQL server 动态查询(表名或字段动态),并且获取想得到的返回值结果
    软件开发中,这些文档你用到了吗
  • 原文地址:https://www.cnblogs.com/salty/p/2001798.html
Copyright © 2011-2022 走看看