C#基于Windows服务的聊天程序(1)

本文将演示怎么通过C#开发部署一个Windows服务,该服务提供各客户端的信息通讯,适用于局域网。采用TCP协议,单一服务器连接模式为一对多;多台服务器的情况下,当客户端连接数超过预设值时可自动进行负载转移,当然也可手动切换服务器,这种场景在实际项目中应用广泛。

简单的消息则通过服务器转发,文件类的消息则让客户端自己建立连接进行传输。后续功能将慢慢完善。

自定义协议:

1.新建Windows服务项目

2.修改配置文件添加

<appSettings>
  <add key="maxQueueCount" value="10"/>
  <add key="failoverServer" value="192.168.250.113,192.168.250.141"/>
</appSettings>

说明:maxQueueCount为最大连接数,failoverServer故障转移备用服务器(多个服务器,隔开)

3.打开ChatService右键添加安装程序,此时会自动添加ProjectInstaller.cs文件,文件中会默认添加serviceProcessInstaller1和serviceInstaller1两个组件

修改serviceInstaller1和serviceProcessInstaller1的属性信息如图

StartType属性说明:

  Automatic 指示服务在系统启动时将由(或已由)操作系统启动。如果某个自动启动的服务依赖于某个手动启动的服务,则手动启动的服务也会在系统启动时自动启动。

  Disabled 指示禁用该服务,以便它无法由用户或应用程序启动。

  Manual 指示服务只由用户(使用“服务控制管理器”)或应用程序手动启动。

Account属性说明:

  LocalService    充当本地计算机上非特权用户的帐户,该帐户将匿名凭据提供给所有远程服务器。

  LocalSystem    服务控制管理员使用的帐户,它具有本地计算机上的许多权限并作为网络上的计算机。

  NetworkService    提供广泛的本地特权的帐户,该帐户将计算机的凭据提供给所有远程服务器。

  User    由网络上特定的用户定义的帐户。如果为 ServiceProcessInstaller.Account 成员指定 User,则会使系统在安装服务时提示输入有效的用户名和密码,除非您为 ServiceProcessInstaller 实例的 Username 和 Password 这两个属性设置值。

4.完成以后打开ChatService代码,重写OnStart和OnStop方法(即服务的启动和停止方法)。若要重写其它方法请在ServiceBase中查看。

5.在项目中添加服务注册和卸载脚本文件

Install.bat
@echo off
path %SystemRoot%\Microsoft.NET\Framework\v4.0.30319;%path%
installutil %~dp0\WindowsChat.exe
%SystemRoot%\system32\sc failure "ChatService" reset= 30 actions= restart/1000
pause
@echo on

Uninstall.bat
@echo off
path %SystemRoot%\Microsoft.NET\Framework\v4.0.30319;%path%
installutil -u %~dp0\WindowsChat.exe
pause
@echo on

说明:%~dp0 表示bat文件所在的目录

文件属性选择 始终复制-内容,这样才能生成到输出文件夹中

6.回到上面的重写OnStart和OnStop方法

创建一个SocketHelper类

namespace WindowsChat
{
  public delegate void WriteInfo(string info);

  public class SocketHelper
  {
    #region 构造函数
    public SocketHelper()
    {
    }
    public SocketHelper(WriteInfo method)
    {
      this.method = method;
    }
    #endregion

    public static Socket LocalSocket = null;
    private object lockObj = new object();
    public static List<Socket> Clients = new List<Socket>();
    private WriteInfo method = null;

    /// <summary>
    /// 创建Socket
    /// </summary>
    /// <param name="port">端口默认 11011</param>
    /// <param name="backlog">The maximum length of the pending connections queue.</param>
    /// <returns></returns>
    public Socket Create(int port = 11011, int backlog = 100)
    {
      if (LocalSocket == null)
      {
        IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Any, port);//本机预使用的IP和端口
        LocalSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        LocalSocket.Bind(ipEndPoint);
        LocalSocket.Listen(backlog);
      }
      return LocalSocket;
    }

    /// <summary>
    /// 查找客户端连接
    /// </summary>
    /// <param name="id">标识</param>
    /// <returns></returns>
    private Socket FindLinked(string id)
    {
      foreach (var item in Clients)
      {
        if (item.RemoteEndPoint.ToString() == id)
          return item;
      }
      return null;
    }

    /// <summary>
    /// 接受远程连接
    /// </summary>
    public void Accept()
    {
      if (LocalSocket != null)
      {
        while (true)
        {
          Socket client = LocalSocket.Accept();
          Thread thread = new Thread(new ParameterizedThreadStart(Revice));
          thread.Start(client);
          WriteLog("客户端:" + client.RemoteEndPoint.ToString() + " 接入");
          lock (lockObj)
          {
            Clients.Add(client);
          }
          BroadCast("ADD|" + client.RemoteEndPoint.ToString());
        }
      }
    }

    /// <summary>
    /// 日志
    /// </summary>
    /// <param name="info">信息</param>
    private void WriteLog(string info)
    {
      using (FileStream fs = new FileStream("C:\\chatservice.txt", FileMode.Append, FileAccess.Write, FileShare.ReadWrite))
      {
        using (StreamWriter sw = new StreamWriter(fs, Encoding.UTF8))
        {
          sw.WriteLine(info);
        }
      }
      if (method != null)
      {
        method(info);
      }
    }

    /// <summary>
    /// 广播
    /// </summary>
    /// <param name="info">信息</param>
    public void BroadCast(string info)
    {
      foreach (var item in Clients)
      {
        try
        {
          item.Send(Encoding.UTF8.GetBytes(info));
        }
        catch (Exception ex)
        {
          WriteLog(item.RemoteEndPoint.ToString() + ex.Message);
          continue;
        }
      }
    }

    /// <summary>
    /// 介绍信息
    /// </summary>
    /// <param name="client"></param>
    public void Revice(object client)
    {
      Socket param = client as Socket;
      var remoteName = param.RemoteEndPoint.ToString();
      if (param != null)
      {
        int res = 0;
        while (true)
        {
          byte[] buffer = new byte[10240];
          int size = param.ReceiveBufferSize;
          try
          {
            res = param.Receive(buffer);
          }
          catch (SocketException ex)
          {
            if (ex.SocketErrorCode == SocketError.ConnectionReset)
            {
              Clients.Remove(param);
              WriteLog("客户端:" + remoteName + "断开连接1");
              BroadCast("REMOVE|" + remoteName);
              param.Close();
              return;
            }
          }

          if (res == 0)
          {
            Clients.Remove(param);
            WriteLog("客户端:" + remoteName + "断开连接2");
            BroadCast("REMOVE|" + remoteName);
            param.Close();
            return;
          }
          var clientMsg = Encoding.UTF8.GetString(buffer, 0, res);
          WriteLog(string.Format("收到客户端{0}命令:{1}", remoteName, clientMsg));
          if (clientMsg == "GETALL")
          {
            StringBuilder sb = new StringBuilder();
            foreach (var item in Clients)
            {
              sb.AppendFormat("{0}|", item.RemoteEndPoint.ToString());
            }
            param.Send(Encoding.UTF8.GetBytes("ALL|" + sb.ToString()));
          }
          else if (clientMsg == "OFFLINE")
          {
            if (Clients.Contains(param))
            {
              Clients.Remove(param);
              WriteLog("客户端:" + remoteName + "断开连接2");
              BroadCast("REMOVE|" + remoteName);
              param.Close();
              return;
            }
          }
          else if (clientMsg.StartsWith("TRANST|"))
          {
            var msgs = clientMsg.Split('|');
            var toSocket = FindLinked(msgs[1]);
            if (toSocket != null)
            {
              WriteLog(remoteName + "发给" + msgs[1] + "的消息" + msgs[2]);
              toSocket.Send(Encoding.UTF8.GetBytes("TRANSF|" + remoteName + "|" + msgs[2]));
            }
          }
        }
      }
    }
  }
}

重写OnStart和OnStop方法

public partial class ChatService : ServiceBase
{
    SocketHelper helper;
    Thread mainThread;

    public ChatService()
    {
      InitializeComponent();
    }

    protected override void OnStart(string[] args)
    {
      if (helper == null)
      {
        helper = new SocketHelper();
      }
      helper.Create();
      mainThread = new Thread(new ThreadStart(helper.Accept));
      mainThread.IsBackground = true;
      mainThread.Start();
    }

    protected override void OnStop()
    {
      helper.BroadCast("SHUTDOWN");
    }
}

至此一个简易的Windows服务的聊天服务端开发完成,后续会在这基础上进行扩展。

运行install.bat(以管理员身份运行)如图

7.运行 services.msc查找到ChatService服务,能正常启动停止说明部署成功!

当然你也可以将InstallUtil.exe拷贝到执行文件所在目录,比如c:\bin\

则部署脚本为

  cd c:\bin\

  InstallUtil WindowsChat.exe

  卸载脚本

  InstallUtil -u WindowsChat.exe

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • C#启动windows服务方法的相关问题分析

    C#启动windows服务的方法都是什么呢?C#启动服务类型为Disabled的windows服务会遇到什么样的问题呢?那么本文就向你介绍C#启动windows服务的方法的相关内容. C#启动windows服务的方法是什么呢?来让我们开始吧: C#启动windows服务的由来:我们知道, 在C#代码中启动一个已经存在的windows服务,我们可以用这样的代码来完成: 复制代码 代码如下: //ACPI is an example of service name System.ServicePro

  • c#使用windows服务更新站点地图的详细示例

    由于公司平台访问人数逐渐增多,公司项目的数据库已经几次出现宕机现象.为减轻数据库压力,我上个月对公司项目做了下调整.把新闻板块提取出来单独一个站点,单独一个数据库.减少了主站点和数据库的负担和压力. 但放在线上一个月,新闻新的发布数量最少已经有500篇左右.百度只收录了70个左右,于是想到可能是没有站点地图造成的.但怎么定时更新站点地图呢? 我尝试使用windows服务来定时更新站点地图. 首先需要了解下几个问题. 1.百度收录的站点地图(sitemap)的格式.详情请查看该链接:查看 目前我只

  • C#编写Windows服务实例代码

    Microsoft Windows 服务(即,以前的 NT 服务)使您能够创建在它们自己的 Windows 会话中可长时间运行的可执行应用程序.这些服务可以在计算机启动时自动启动,可以暂停和重新启动而且不显示任何用户界面.这使服务非常适合在服务器上使用,或任何时候,为了不影响在同一台计算机上工作的其他用户,需要长时间运行功能时使用.还可以在不同于登录用户的特定用户帐户或默认计算机帐户的安全上下文中运行服务. 使用Microsoft Visual Studio2012可以很方便的创建一个Windo

  • c#创建windows服务(Windows Services)详细步骤

    Windows服务在Visual Studio 以前的版本中叫NT服务,在VS.net启用了新的名称.用Visual C# 创建Windows服务不是一件困难的事,本文就将指导你一步一步创建一个Windows服务并使用它.这个服务在启动和停止时,向一个文本文件中写入一些文字信息. 第一步:创建服务框架 要创建一个新的 Windows 服务,可以从Visual C# 工程中选取 Windows 服务(Windows Service)选项,给工程一个新文件名,然后点击 确定.你可以看到,向导向工程文

  • C#使用windows服务开启应用程序的方法

    本文实例讲述了C#使用windows服务开启应用程序的方法.分享给大家供大家参考.具体如下: 使用windows服务开启应用程序,会遇到如下问题 1.使用windows服务开启的应用程序不会显示应用程序界面 解决方法:当安装服务之后,选中服务,点击属性->登录,然后设置登录身份为本地系统账户,并允许服务与桌面进行交互 2.使用的是远程桌面进行查看,不会显示界面 解决方法:不能直接使用mstsc命令进入远程桌面,要使用mstsc /v:192.168.1.10 /admin命令 ,这里192.16

  • c#创建windows服务入门教程实例

    用c#中创建一个windows服务非常简单,与windows服务相关的类都在System.ServiceProcess命名空间下. 每个服务都需要继承自ServiceBase类,并重写相应的启动.暂停.停止等方法. windows服务的相关信息是存放与注册表中的,所以他可以在不需要用户登录的情况下自动运行,在c#中你不需要再直接向注册表中添加信息了,c#提供了服务安装类 ServiceProcessInstaller和ServiceInstaller来实现服务的安装. 首先,用vs创建一个win

  • c# 在windows服务中 使用定时器实例代码

    由于最近做自动执行的程序,开始做windows服务程序, 在windows服务中如何使用定时器的时候一直失效, 以前是直接拖入timer控件,但是不能直接运行,后来在网上找了一段程序,好使了. 复制代码 代码如下: //开始事件        protected override void OnStart(string[] args)        {             //定时事件            MyTimer();         } //结束事件        protect

  • 使用C#创建Windows服务的实例代码

    本文介绍了使用C#创建Windows服务的实例代码,分享给大家 一.开发环境 操作系统:Windows 10 X64 开发环境:VS2015 编程语言:C# .NET版本:.NET Framework 4.0 目标平台:X86 二.创建Windows Service 1.新建一个Windows Service,并将项目名称改为"MyWindowsService",如下图所示: 2.在解决方案资源管理器内将Service1.cs改为MyService1.cs后并点击"查看代码&

  • C#开发Windows服务实例之实现禁止QQ运行

    本实例主要实现下面三个基本功能 1.C#开发windows服务 2.禁止QQ等程序运行 3.为windows服务创建自动安装程序 下面针对这三个基本功能进行实现 一.C#开发windows服务 Windows服务在VS以前的版本中叫NT服务,在VS.NET启用了新的名称.用C#创建windows服务不是一件困难的事,下页针对服务创建.启动.停止做详细介绍 1.首先在vs中添加一winform程序KillService 2.在解决方案添加新项中添加Windows服务 3.打开服务页面,切换至代码页

  • 基于C#实现Windows服务状态启动和停止服务的方法

    本文以实例形式展示了基于C#实现Windows服务状态启动和停止服务的方法.非常实用.分享给大家供大家参考之用.具体方法如下: 首先先引用: System.ServiceProcess.dll 然后在引用命名空间: using System.ServiceProcess; 建立服务对象: ServiceController sc = new ServiceController("Server"); 服务运行则停止服务: if (sc.Status.Equals(ServiceContr

  • C#启动和停止windows服务的实例代码

    复制代码 代码如下: <script type="text/javascript">        function showLoading(desc) {            $("body").append("<div id=\"processingdiv\" style=\"display:none;\"><div class=\"popup\"> &l

  • C#编写Windows服务程序详细步骤详解(图文)

    一.创建一个Windows Service 1)创建Windows Service项目 2)对Service重命名 将Service1重命名为你服务名称,这里我们命名为ServiceTest. 二.创建服务安装程序 1)添加安装程序 之后我们可以看到上图,自动为我们创建了ProjectInstaller.cs以及2个安装的组件. 2)修改安装服务名 右键serviceInsraller1,选择属性,将ServiceName的值改为ServiceTest. 3)修改安装权限 右键servicePr

  • C#使用windows服务发送邮件

    最近做了一个使用 C# 写了一个发送邮件的windows 服务,在这里记录一下. 首先使用 Visual Studio 2015 创建一个 windows 服务项目. 然后在设计器上面右击添加安装程序.如下图. 安装好后,选择安装程序设计界面,选择服务和安装程序右击选择属性修改一些属性值. PS:如果不给服务添加安装程序,后面是没法把服务安装至 windows 系统里的. 在数据库创建一个表,用于存储需要发送的邮件信息. create table MainInfo ( MainInfoID in

  • C#添加Windows服务 定时任务

    本文实例为大家分享了C#添加Windows服务的具体方法,供大家参考,具体内容如下 源码下载地址:http://xiazai.jb51.net/201701/yuanma/Windowsservice1(jb51.net).rar 步骤一.创建服务项目. 步骤二.添加安装程序. 步骤三.服务属性设置 [serviceInstaller1]. 4.1 添加定时任务 public partial class SapSyn : ServiceBase { System.Timers.Timer tim

  • C#版Windows服务安装卸载小工具

    前言  在我们的工作中,经常遇到Windows服务的安装和卸载,在之前公司也普写过一个WinForm程序选择安装路径,这次再来个小巧灵活的控制台程序,不用再选择,只需放到需要安装服务的目录中运行就可以实现安装或卸载. 开发思路 1.由于系统的权限限制,在运行程序时需要以管理员身份运行 2.因为需要实现安装和卸载两个功能,在程序运行时提示本次操作是安装还是卸载  需要输入 1 或 2  3.接下来程序会查找当前目录中的可执行文件并过滤程序本身和有时我们复制进来的带有vhost的文件,并列出列表让操

  • C#通过创建Windows服务启动程序的方法详解

    本文实例讲述了C#通过创建Windows服务启动程序的方法.分享给大家供大家参考,具体如下: 1. 新建一个Windows服务应用程序 创建项目-->Visual C# 左侧的"+"-->Windows -->Windows 服务(右侧模板)-->输入名称,确定创建项目 2. 设置Windows服务的属性(Windows服务里没有窗体,所以点击左侧设计器里空白的地方即可在右侧属性栏里看到属性) 这里属性是控制服务器是否可以停止,暂停,继续等等的操作.根据需要选择

  • c#开发的程序安装时动态指定windows服务名称

    这下可把我难住了,难道要 在开发的代码中一个一个地设置想要的名称,然后重新编译,再注册成服务? 但是如果将来又要换个名称呢?再重新设置. 编译.注册一遍?这样操作太麻烦了! 于是我就想能不能通过在安装的时候进行配置,比如加一个xml文件记录要安装的服务的服务名等信息,每次安装前修改该xml文件就可以了. 操作: 1.首先添加一个配置文件到服务主程序的根目录,取名"ServiceSetting.xml": 复制代码 代码如下: <?xml version="1.0&quo

随机推荐