总结
#通过下面两小题熟悉c#的基础语法,还有c#网络编程。作为c#游戏服务端开发入门的两道基础习题。
。
一、实现一个简单的服务端,要求能解析请求的字符串,并根据字符串里的服务名和接口名调用到对应的实际方法,并传入字符串中包含的参数
请求字符串示例:
{“parameter1”: 1234, “parameter2”: “daqing”, “cmd”: “TestService.Enter”}
1.Program.cs类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace post
{
class Program
{
static void Main(string[] args)
{
ServerControl server = new ServerControl();
server.start();
Console.ReadKey();
}
}
}
2.ServerControl.cs类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace post
{
public class ServerControl
{
private Socket serverSocket;
private List<Socket> clientList;
public ServerControl()
{
serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//创建服务器端socket ipv4, 流式传输, tcp协议
clientList = new List<Socket>();
}
public void start()
{
serverSocket.Bind(new IPEndPoint(IPAddress.Any, 8080)); //绑定IP 及 端口 IPAddress.Any 表示程序运行在的机器IP地址
serverSocket.Listen(10);// 监听 端口上 客户端的连接,排队等待连接的最大数量
Console.WriteLine("服务器启动成功");
Thread threadAccept = new Thread(accept);//创建一个接受客户端连接的线程 该线程机制可以接受多个客户端连接
threadAccept.IsBackground = true;//后台执行
threadAccept.Start();//启动线程
}
private void accept()
{
while (true)
{
//接受客户端连接,并返回socket, 该方法会阻塞挂起当前线程
Socket client = serverSocket.Accept();
IPEndPoint point = client.RemoteEndPoint as IPEndPoint; //远程连接过来IP 指客户端IP
Console.WriteLine(point.Address + "[" + point.Port + "]" + "连接成功");
clientList.Add(client);
Thread thradReceive = new Thread(receive);//开启一个新线程用于接收数据
thradReceive.IsBackground = true;
thradReceive.Start(client);
//Console.WriteLine("服务器启动成功");
}
}
public void GetAndExecuteMethod(string className, string methodName, object[] parameters)
{
try
{
//命名空间.类
Type type = Type.GetType("post." + className);
if (type == null)
throw new NullReferenceException("类" + className + "不存在");
Object obj = Activator.CreateInstance(type);
MethodInfo[] info = type.GetMethods();
for (int i = 0; i < info.Length; i++)
{
var md = info[i];
string mothodName = md.Name;
//方法名相同且参数个数一样
if (mothodName == methodName)
{
md.Invoke(obj,parameters);
}
}
}
catch (Exception e)
{
throw e;
}
}
private void receive(Object obj)
{
while (true)
{
Socket client = obj as Socket;
IPEndPoint point = client.RemoteEndPoint as IPEndPoint;
try
{
byte[] msg = new byte[1024];//申请一块字节数组用于存放接收的数据
int msgLen = client.Receive(msg);//接收字节数组 返回接收的长度 该函数会阻塞所在的线程 所以放到新线程中
string msgStr = Encoding.UTF8.GetString(msg, 0, msgLen); //转换字节数组成字符串 并输出
Parameter rb = JsonConvert.DeserializeObject<Parameter>(msgStr);
//ParameterTest rbTest = JsonConvert.DeserializeObject<ParameterTest>(msgStr);
string[] s = (rb.cmd).Split('.');
object[] parameters = new object[] {rb};
//将类名的字符串及方法名的字符串传递过去
GetAndExecuteMethod(s[0], s[1],parameters);
//服务器返回响应
broadcast(client, msgStr);
break;
}
catch
{
Console.WriteLine(point.Address + "[" + point.Port + "]" + "积极断开");
clientList.Remove(client);
break;
}
}
}
private void broadcast(Socket clientOther, string msg)
{
foreach (var client in clientList)
{
if (client == clientOther)
{
//TestService testservice = new TestService();
//Console.WriteLine("服务器返回响应");
//client.Send(Encoding.UTF8.GetBytes(msg+"收到后,"));
}
else
{
client.Send(Encoding.UTF8.GetBytes(msg));
}
}
}
}
}
3.Parameter.cs类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace post
{
class Parameter
{
public int parameter1 { get; set; }
//public int parameter2 { get; set; }
public string parameter2 { get;set; }
public string cmd { get; set; }
}
}
4.TestService.cs类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace post
{
class TestService
{
public void Enter(int parameter1,string parameter2)
{
Console.WriteLine("调用TestService类的Enter方法,输出参数的值");
Console.WriteLine("parameter1:{0}",parameter1);
Console.WriteLine("parameter2:{0}",parameter2);
}
}
}
二、2. 实现一个程序,可以读取一份Excel文档里的数据,并将其写入到对应的数据库表,要求使用创建model类和特性来实现Excel中文列名到数据库表字段的通用转换。
示例表:
CREATE TABLE [dbo].[user-info](
[Id] [int] NOT NULL,
[UserName] varchar NOT NULL,
[Gold] [int] NOT NULL,
[Silver] [bigint] NOT NULL,
PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
1.Program.cs类
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.OleDb;
using System.Data.SqlClient;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace lianjieTest
{
class Program
{
static void Main(string[] args)
{
connection();
Console.ReadKey();
}
public static int connection()
{
//数据库连接串
string connStr = "Data source=.;Initial Catalog=test;Trusted_Connection=SSPI";
SqlConnection sql = new SqlConnection(connStr);
try
{
sql.Open();
DataSet ds = ExcelToDataSet("D:\\wanjiaxinxibiao.xlsx");
for (int i = 0; i < ds.Tables[0].Rows.Count; i++)
{
List<object> list = new List<object>();
List<object> list1 = new List<object>();
model p = new model();
Type t = p.GetType();
foreach (PropertyInfo pi in t.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
{
object[] Attribute = pi.GetCustomAttributes(false);
MarkAttribute myTest = Attribute[0] as MarkAttribute;
//将遍历类属性,根据model类属性去读取相应的excel表格
object v = Convert.ChangeType(ds.Tables[0].Rows[i][myTest.FiledName].ToString(), t.GetProperty(pi.Name).PropertyType);
t.GetProperty(pi.Name).SetValue(p, v, null);
list.Add(pi.Name);
list1.Add(Convert.ToString(t.GetProperty(pi.Name).GetValue(p, null)));
}
//将每个属性的值拼接成sql操作操作语句
string str1 = "insert into [user-info] (";
string str2 = string.Join(",",list.ToArray());
string str3 = ") values('"+string.Join("','", list1.ToArray());
string str4 = "')";
string str = str1 + str2 + str3 + str4;
//执行sql命令插入
SqlCommand command = new SqlCommand(str, sql);
command.ExecuteNonQuery();
}
Console.WriteLine("导入数据库成功");
}
catch (Exception ex)
{
Console.WriteLine("导入数据库失败");
throw ex;
}
finally
{
if (sql != null)
{
//关闭数据库连接
sql.Close();
}
}
return 0;
}
public static DataSet ExcelToDataSet(string filename)
{
string strCon = "Provider=Microsoft.Jet.OLEDB.4.0;" +
"Extended Properties=Excel 8.0;" +
"data source=" + filename;
OleDbConnection myConn = new OleDbConnection(strCon);
//"玩家信息"为表单标签页名
string strCom = " SELECT * FROM [玩家信息$]";
myConn.Open();
OleDbDataAdapter myCommand = new OleDbDataAdapter(strCom, myConn);
DataSet ds;
ds = new DataSet();
myCommand.Fill(ds, "玩家信息");
myConn.Close();
return ds;
}
}
}
2.MarkAttribute.cs类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace lianjieTest
{
[AttributeUsage(AttributeTargets.Property, Inherited = false, AllowMultiple = true)]
class MarkAttribute : Attribute
{
public MarkAttribute(string markname)
{
this.FiledName = markname;
}
public string FiledName
{
get;
set;
}
}
}
3.model.cs类
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace lianjieTest
{
class model
{
[Mark("玩家编号")]
public int Id { get; set; }
[Mark("玩家昵称")]
public string UserName { get; set; }
[Mark("元宝数量")]
public int Gold { get; set; }
[Mark("银两数量")]
public long Silver { get; set; }
}
}