超详细的TCP、Sokcket和SuperSocket与TCP入门指导
kiba518脚本之家 作者 |kiba518 出品 | 脚本之家(ID:jb51net) 前言 本文主要介绍TCP、Sokcket和SuperSocket的基础使用。 创建实例模式的SuperSocket服务 首先创建控制台项目,然后Nuget添加引用SuperSocket.Engine。 然后编写服务代码,SuperSocket的服务代码主要是配置AppServer对象,因为AppServer已经很好的封装端口监听了。 代码如下所示: class Program { static AppServer appServer { get; set; } static void Main(string[] args) { var serverConfig = new SuperSocket.SocketBase.Config.ServerConfig(); serverConfig.Port = 5180; serverConfig.TextEncoding = "gb2312"; serverConfig.MaxConnectionNumber = 1000; appServer = new AppServer(); //配置 if (!appServer.Setup(serverConfig)) { Console.WriteLine("配置失败!"); return; } //启动 if (!appServer.Start()) { Console.WriteLine("启动失败!"); return; } Console.WriteLine("启动成功,按Q退出!"); appServer.NewSessionConnected += new SessionHandler<AppSession>(appServer_NewSessionConnected); appServer.SessionClosed += appServer_NewSessionClosed; appServer.NewRequestReceived += new RequestHandler<AppSession, StringRequestInfo>(appServer_NewRequestReceived); while (Console.ReadKey().KeyChar != 'q') { continue; } //停止 appServer.Stop(); Console.WriteLine("服务已停止"); Console.ReadKey(); } static void appServer_NewSessionConnected(AppSession session) { var count = appServer.SessionCount; Console.WriteLine($"服务端得到来自客户端的连接成功 ,当前会话数量:" + count); //这里也可以向会话的stream里写入数据,如果在这里向流写入数据,则客户端需要在Send之前先接收一次,不然的话,Send后接收的就是这条数据了 session.Send("连接成功"); } static void appServer_NewSessionClosed(AppSession session, CloseReason aaa) { var count = appServer.SessionCount; Console.WriteLine($"服务端 失去 来自客户端的连接" + session.SessionID + aaa.ToString()+ " 当前会话数量:" + count); } static void appServer_NewRequestReceived(AppSession session, StringRequestInfo requestInfo) { Console.WriteLine($"Key:" + requestInfo.Key + $" Body:" + requestInfo.Body); session.Send("我是返回值:" + requestInfo.Body); } } AppServer:AppServer是SuperSocket中定义的Socket服务类,他替我们实现了复杂的端口监听,不用再写While循环,不用再关心线程阻塞的问题,在监听端口在这里,我们只要调用AppServer的对象的Start方法,就可以了;AppServer还提供了一个配置文件类—ServerConfig,通过它,我们可以配置具体监听的端口、并发数量、编码、最大传输字节数、传输模式(TCP/UDP)等等属性;此外还提供三个重要事件:会话连接启动事件(NewSessionConnected)、会话关闭事件(SessionClosed)、请求接受事件(NewRequestReceived)。 注:文中在连接成功的事件中,我们向客户端发送消息了,即,客户端在连接后,发送消息前,需要接收该信息。 创建TCP发送消息客户端 服务建立后,我们建立客户端。 代码如下所示: staticvoidMain(string[]args){TCPConnect("127.0.0.1",5180);Console.ReadKey();}staticvoidTCPConnect(Stringserver,Int32port){stringmessage=$"ADDkiba518518"+"\r\n";try{TcpClientclient=newTcpClient();client.Connect(server,port);Byte[]data=System.Text.Encoding.Default.GetBytes(message);StringresponseData=String.Empty;NetworkStreamstream=client.GetStream();byte[]buffer=newbyte[1024*1024*2];Int32bytes=stream.Read(buffer,0,buffer.Length);responseData=System.Text.Encoding.Default.GetString(buffer,0,bytes);Console.WriteLine("接收服务器在连接事件中写入的数据:{0}",responseData);stream.Write(data,0,data.Length);Console.WriteLine("发送数据:{0}",message);data=newByte[256];bytes=stream.Read(buffer,0,buffer.Length);responseData=System.Text.Encoding.Default.GetString(buffer,0,bytes);Console.WriteLine("接收返回值:{0}",responseData);stream.Close();client.Close();}catch(ArgumentNullExceptione){Console.WriteLine("ArgumentNullException:{0}",e.Message);}catch(SocketExceptione){Console.WriteLine("SocketException:{0}",e.Message);}Console.Read();} 代码很简单,就是使用TcpClient连接服务器的IP和端口,然后发送消息。 因为我们使用的SuperSocket,有格式要求,所以我们需要准守。 格式要求如下: 命令名称+空格+参数+参数+...参数+"\r\n" 对应的字符串如下: $"ADD kiba518 518" + "\r\n" 因为上文中,服务在连接成功后就向客户端发送的流中写入了数据,所以,我们在Send消息前,先接收一下流中的数据。 客户端与服务联调 先运行服务,在运行客户端,结果服务端与客户端成功的完成了一次通信,如下图所示: 为了更清晰的了解通信内容,我们在服务接收消息事件中断点,如下图: 可以看到参数requestInfo完整的解析了我们发送的字符串【"ADD kiba518 518" + "\r\n"】。 创建配置模式的SuperSocket服务 现在我们创建一个配置模式的SuperSocket服务,这种模式客户通过配置创建多个SuperSocket,即可以在一个项目里通过配置监听多个端口,这里,我们只做一个端口监听的配置例子。 与实例模式的开始一样,先创建一个控制台程序,然后Nuget添加引用SuperSocket.Engine。 然后进行三步操作。 一,编写Main函数,启动SuperSocket,通过启动引导工厂BootstrapFactory实例化一个启动引导对象,然后初始化化,该初始化会遍历当前项目中所有继承了AppServer的类,然后调用他们的Start方法,代码如下所示: static void Main(string[] args){ #region 初始化Socket IBootstrap bootstrap = BootstrapFactory.CreateBootstrap(); if (!bootstrap.Initialize()) { Console.WriteLine(DateTime.Now + ":Socket初始化失败\r\n"); return; } var result = bootstrap.Start(); foreach (var server in bootstrap.AppServers) { if (server.State == ServerState.Running) { Console.WriteLine(DateTime.Now + ":serverName为:" + server.Name + "Socket运行中\r\n"); } else { Console.WriteLine(DateTime.Now + ":serverName为:" + server.Name + "Socket启动失败\r\n"); } } Console.ReadKey(); #endregion} 二,修改App.config配置文件,在configuration节点下,增加superSocket的section,并配置superSocket,代码如下: <configSections><sectionname="superSocket"type="SuperSocket.SocketEngine.Configuration.SocketServiceConfig,SuperSocket.SocketEngine"/></configSections><!--配置SocketServer路径--><superSocket><servers><!--serverType属性有两个参数,第一个是服务类的完全限定名,第二个是服务类的命名空间--><servername="MySocket"textEncoding="gb2312"serverType="SuperSocketServerSessionMode.SocketServer,SuperSocketServerSessionMode"ip="Any"port="5180"maxConnectionNumber="100"></server></servers></superSocket> 三,创建SocketServer类、SocketSession类、SocketCommand类。 SocketServer类:继承泛型AppServer(其泛型类指定一个会话类)该类用于创建SuperSocket的服务并监听端口;其Setup方法,默认读取App.config配置文件中的superSocket节点—servers节点—server节点;读取时根据server的serverType属性匹配读取。 publicclassSocketServer:AppServer<SocketSession>{protectedoverrideboolSetup(IRootConfigrootConfig,IServerConfigconfig){Console.WriteLine("正在准备配置文件");returnbase.Setup(rootConfig,config);}protectedoverridevoidOnStarted(){Console.WriteLine("服务已开始");base.OnStarted();}protectedoverridevoidOnStopped(){Console.WriteLine("服务已停止");base.OnStopped();}protectedoverridevoidOnNewSessionConnected(SocketSessionsession){Console.WriteLine("新的连接地址为"+session.LocalEndPoint.Address.ToString()+",时间为"+DateTime.Now);base.OnNewSessionConnected(session);}} SocketSession类:继承AppSession,是SuperSocket的会话类。 如果客户端所发送的消息不合法,则会被会话的HandleUnknownRequest函数截获,如果合法,则发送到指定的命令类中。 代码如下: publicclassSocketSession:AppSession<SocketSession>{publicoverridevoidSend(stringmessage){Console.WriteLine("发送消息:"+message);base.Send(message);}protectedoverridevoidOnSessionStarted(){Console.WriteLine("Session已启动");base.OnSessionStarted();}protectedoverridevoidOnInit(){this.Charset=Encoding.GetEncoding("gb2312");base.OnInit();}protectedoverridevoidHandleUnknownRequest(StringRequestInforequestInfo){Console.WriteLine($"遇到未知的请求Key:"+requestInfo.Key+$"Body:"+requestInfo.Body);base.HandleUnknownRequest(requestInfo);}} SocketCommand类:是SuperSocket的命令类,定义明确的会话命令;类名即客户端发送消息的第一个空格前的字符串。 代码如下: publicclassSocketCommand:CommandBase<SocketSession,StringRequestInfo>{publicoverridevoidExecuteCommand(SocketSessionsession,StringRequestInforequestInfo){//根据参数个数或者其他条件判断,来进行一些自己的操作Console.WriteLine($"调用成功Key:"+requestInfo.Key+$"Body:"+requestInfo.Body);session.Send("已经成功接收到你的请求\r\n");}} 创建配置模式的SuperSocket客户端 创建一个配置模式的SuperSocket客户端,这一次我们使用Socket类创建。 代码如下: staticSocketsocketClient{get;set;}staticvoidMain(string[]args){socketClient=newSocket(SocketType.Stream,ProtocolType.Tcp);IPAddressip=IPAddress.Parse("127.0.0.1");IPEndPointpoint=newIPEndPoint(ip,5180);socketClient.Connect(point);Threadthread=newThread(Recive);//不停的接收服务器端发送的消息thread.Start();Threadthread2=newThread(Send);//不停的给服务器发送数据thread2.Start();}staticvoidRecive(){while(true){//获取发送过来的消息byte[]buffer=newbyte[1024*1024*2];vareffective=socketClient.Receive(buffer);if(effective==0){break;}varstr=Encoding.Default.GetString(buffer,0,effective);Console.WriteLine("服务器---"+str);Thread.Sleep(2000);}}staticvoidSend(){inti=0;intparam1=0;intparam2=0;while(true){i++;param1=i+1;param2=i+2;Console.WriteLine($"Sendi:{i}param1:{param1}param2:{param2}");stringmsg=$"SocketCommand{param1}{param2}"+"\r\n";Console.WriteLine($"msg:{msg}");varbuffter=Encoding.Default.GetBytes(msg);vartemp=socketClient.Send(buffter);Console.WriteLine($"Send发送的字节数:{temp}");Thread.Sleep(1000);}} 可以看到Socket的使用方式与Tcp的使用方式几乎相同,都是指定IP和端口号,只是Socket多了一步,需要指定协议类型ProtocolType,这里我们指定了是TCP。 客户端与服务联调 先运行服务,在运行客户端,结果通信成功,如下图所示: 到此TCP、Sokcket和SuperSocket的基本使用已经介绍完了,代码已经传到Github上了,欢迎大家下载。 Github地址:https://github.com/kiba518/SuperSocketConsole 本文作者:kiba518,.NET系统架构师 声明:本文为 脚本之家专栏作者 投稿,未经允许请勿转载。