好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

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

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

dy("nrwz");

查看更多关于C#基于Windows服务的聊天程序(1)的详细内容...

  阅读:42次