ServerSocket

服务器与客户端建立连接的流程

通信流程

在SimpleServer的Net文件夹内新建ServerSocket

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
using System.Net.Sockets;
using System.Net;

namespace SimpleServer.Net
{
internal class ServerSocket : SingletonPattern<ServerSocket>
{
//公钥
public static string PublicKey = "ATAOServer";
//密钥,后续可以随时间进行变化
public static string SecretKey = "ATAO_UP&&jiiEf=Ted";
#if DEBUG
private string m_IPAddress = "127.0.0.1";
#else
//对应腾讯云或阿里云的本地IP地址,注意不是访问时用到的公网IP地址,而是从公网电脑上使用IPConfig测出来的地址。
private string m_IPAddress = "172.56.756.31";
#endif
private const int m_Port = 8011;
//服务器监听Socket
private static Socket? m_ListenSocket;
//临时保存所有Select过后可读Socket集合
private static List<Socket> m_CheckReadList = new List<Socket>();

public void Init()
{
IPAddress ip = IPAddress.Parse(m_IPAddress);
IPEndPoint iPEndPoint = new IPEndPoint(ip, m_Port);

m_ListenSocket = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
m_ListenSocket.Bind(iPEndPoint);
m_ListenSocket.Listen(50000);
}

}
}

Log4Net

服务器需要有自己的Log工具,关于基本的log工具应该怎么设计,见下面的文章:

浅谈LOG日志的写法 - 星朝 - 博客园 (cnblogs.com)

总之,Log工具帮助及时Debug,并且还需要将日志保存到本地。

这里封装一下Log4Net插件作为日志工具。

在ServerBase工程中添加一个类,命名为Debug

点击“工具——NuGet包管理器——管理解决方案的NuGet程序包”,在弹出的窗口中搜索“log4net”,安装在ServerBase项目内。

config

要使用Log4Net,首先需要编写Log的配置,现放一个Log4net配置参考文章:

Log4net 配置详解 - 虔城墨客 - 博客园 (cnblogs.com)

Log4Net详解_log4net配置文件详解_李宥小哥的博客-CSDN博客

log4Net官网的config例子Apache log4net – Apache log4net: Config Examples - Apache log4net

在ServerBase项目内添加log4net.config文件,文件内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="log4net" type="System.Configuration.IgnoreSectionHandler"/>
</configSections>
<log4net>
<root>
<level value="All"/>
<appender-ref ref="RollingLogFileAppender"/>
<appender-ref ref="ConsoleAppender"/>
</root>

<appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
<file value="log\logfile.log"/>
<appendToFile value="true"/>
<Encoding value="UTF-8" />
<!--按日期产生文件夹,文件名[在日期方式与混合方式下使用]日志文件名格式为:2008-08-31.log -->
<param name= "DatePattern" value= "yyyy-MM-dd&quot;.log&quot;"/>
<!--log保留天数-->
<param name= "MaxSizeRollBackups" value= "10"/>
<!--日志文件名是否是固定不变的(是否只写到一个文件中)-->
<param name= "StaticLogFileName" value= "false"/>
<!--按照何种方式产生多个日志文件(日期[Date],文件大小[Size],混合[Composite])-->
<param name="RollingStyle" value="Date" />
<!--每个文件的大小。只在混合方式与文件大小方式下使用,超出大小的在文件名后自动增加1重新命名-->
<param name="maximumFileSize" value="500KB" />
<layout type="log4net.Layout.PatternLayout">
<!--
%d, %date :表示当然的时间
   %p, %level :表示日志的级别
   %c, %logger :表示日志产生的主题或名称,通常是所在的类名,便于定位问题
   %m, %message :表示日志的具体内容
   %n, %newline :换行
%exception :表示异常信息
-->
<param name="ConversionPattern" value="%d [%t] %-5p %c - %m %logger %n" />
</layout>
</appender>

<!-- 控制台显示日志 -->
<appender name="ConsoleAppender" type="log4net.Appender.ManagedColoredConsoleAppender">
<!-- 设置不同级别控制台显示的不同颜色 -->
<mapping>
<level value="INFO" />
<foreColor value="Green" />
</mapping>
<mapping>
<level value="DEBUG" />
<foreColor value="White" />
</mapping>
<mapping>
<level value="WARN" />
<foreColor value="Yellow" />
</mapping>
<mapping>
<level value="ERROR" />
<foreColor value="DarkRed" />
</mapping>
<!-- 记录的格式。 -->
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date{HH:mm:ss,fff} [%-5level] %m %n" />
</layout>
<!--
过滤器type有如下几种类型
log4net.Filter.DenyAllFilter 丢弃所有日志事件。
log4net.Filter.LevelMatchFilter 准确匹配事件等级。
log4net.Filter.LevelRangeFilter 匹配一个范围的等级。
log4net.Filter.LoggerMatchFilter 匹配一个日志器名字的开始。
log4net.Filter.PropertyFilter 匹配指定属性名称的子字符串。
log4net.Filter.StringMatchFilter 匹配事件消息的子字符串。
-->
<filter type="log4net.Filter.LevelRangeFilter">
<!-- 控制输出日志的级别范围 -->
<param name="LevelMin" value="DEBUG" />
<param name="LevelMax" value="Error" />
</filter>
</appender>
</log4net>
</configuration>

在解决方案资源管理器中选中“log4net.config”,在下面的“属性”窗口——高级——复制到输出目录——选择“始终复制”。

AssemblyInfo

在解决方案资源管理器中选中“ServerBase”,右键——添加——新建项,在弹出的窗口中选择“程序集信息文件”,命名为AssemblyInfo.cs

在其中添加:

1
[assembly: log4net.Config.XmlConfigurator(ConfigFile ="log4net.config",ConfigFileExtension ="config",Watch = true)]

包装一层Log

在ServerBase里面,新建Debug.cs文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
using log4net;
using log4net.Config;
using System;
using System.IO;

namespace ServerBase
{
public static class Debug
{
private static ILog m_Log;

static Debug()
{
XmlConfigurator.ConfigureAndWatch(new FileInfo(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "log4net.config")));

m_Log = LogManager.GetLogger(typeof(Debug));
}
public static void Log(object message)
{
m_Log.Debug(message);
}
public static void Log(string format, params object[] args)
{
m_Log.DebugFormat(format, args);
}
public static void LogInfo(object message)
{
m_Log.Info(message);
}
public static void LogInfo(string format, params object[] args)
{
m_Log.InfoFormat(format, args);
}
public static void LogWarn(object message)
{
m_Log.Warn(message);
}
public static void LogWarn(string format,params object[] args)
{
m_Log.WarnFormat(format, args);
}
public static void LogError(object message)
{
m_Log.Error(message);
}
public static void LogError(string format, params object[] args)
{
m_Log.ErrorFormat(format, args);
}
public static void LogFatal(object message)
{
m_Log.Fatal(message);
}
public static void LogFatal(string format, params object[] args)
{
m_Log.FatalFormat(format, args);
}
}
}

完善ServerSocket

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public void Init()
{
IPAddress ip = IPAddress.Parse(m_IPAddress);
IPEndPoint iPEndPoint = new IPEndPoint(ip, m_Port);

m_ListenSocket = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
m_ListenSocket.Bind(iPEndPoint);
m_ListenSocket.Listen(50000);

EndPoint? endPoint = m_ListenSocket.LocalEndPoint;

if (endPoint != null )
Debug.LogInfo("服务器启动监听{0}成功",endPoint);

}

Program初始化ServerSocket

1
2
3
4
5
6
7
8
9
10
11
12
13
using SimpleServer.Net;

namespace SimpleServer
{
internal class Program
{
static void Main(string[] args)
{
ServerSocket.Instance.Init();
Console.ReadLine();
}
}
}

Log生成的位置

按照log4net.config的配置,在Debug模式下,log文件的位置为:

1
E:\CSharpProjects\SimpleServer\SimpleServer\bin\Debug\net6.0\log\logfile.log2023-09-08.log