我正在尝试通过试验和错误来学习C#。我有一个Python服务器,C#中的客户端。
客户端应该从服务器获取数据,将其保存到磁盘((它没有)),然后继续使用该数据进行通信,直到用户决定退出它为止。
不幸的是,它已经引发了异常访问冲突很长一段时间,并没有提供有关原因的有用信息。
代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Scripting.Hosting;
using System.Threading;
using Rage;
using System.Net.Sockets;
using System.IO;
[assembly: Rage.Attributes.Plugin("LSPDFROnlineClient", Description = "LSPDFR Online Client. Used to connect to LSPDFR Online.", Author = "Thecheater887")]
namespace LSPDFROnlineClient
{
public class EntryPoint
{
private static int IsDead;
public static void Main()
{
IsDead = 0;
Thread mt = new Thread(new ThreadStart(Run));
mt.Start();
while (true)
{
if (IsDead == 1)
{
break;
}
GameFiber.Yield();
}
return;
}
public static void Run()
{
File.WriteAllText("C:/ProgramData/dbg.log","1");
try
{
Byte[] header;
Byte[] packet;
Byte[] data;
Byte[] kad;
Byte[] td;
int paylen;
String rd;
String nd;
String msgid;
File.WriteAllText("C:/ProgramData/dbg.log", "2");
TcpClient connector = new TcpClient();
connector.Connect("127.0.0.1", 5773);
NetworkStream conn = connector.GetStream();
try {
File.WriteAllText("C:/ProgramData/dbg.log", "3");
FileStream savedat = File.OpenRead("C:/Users/Public/Documents/save.dat");
BinaryReader savdat = new BinaryReader(savedat);
nd = savdat.ReadString();
savdat.Close();
if (nd.Length == 16)
{
} else {
File.WriteAllText("C:/ProgramData/save.dat", "user000000000000");
nd = "user000000000000";
}
}
catch
{
File.WriteAllText("C:/ProgramData/save.dat", "user000000000000");
nd = "user000000000000";
}
File.WriteAllText("C:/ProgramData/dbg.log", "4");
data = new Byte[26];
data = Encoding.ASCII.GetBytes("clogr00000" + nd);
conn.Write(data, 0, data.Length);
while (true)
{
try
{
// Get header of packet
header = new Byte[26];
Int32 rcvhead = conn.Read(header, 0, header.Length);
String hd = Encoding.ASCII.GetString(header, 0, rcvhead);
//Deal with it 8-)
msgid = hd.Substring(0, 5);
paylen = Convert.ToInt32(hd.Substring(5, 5));
string servkey = hd.Substring(10, 16);
}
catch
{
continue;
}
File.WriteAllText("C:/ProgramData/dbg.log", "5");
try
{
//Receive packet data
if (paylen > 0)
{
packet = new Byte[paylen];
Int32 newdata = conn.Read(packet, 0, packet.Length);
rd = Encoding.ASCII.GetString(packet, 0, newdata);
}
else
{
rd = null;
}
File.WriteAllText("C:/ProgramData/dbg.log", "6");
if (msgid == "ConOK")
{
File.WriteAllText("C:/ProgramData/dbg.log", "7");
string userid = rd.Substring(0, 16);
Game.DisplayHelp(rd.Substring(16, (rd.Length - 16)));
File.WriteAllText("C:/ProgramData/save.dat", userid);
File.WriteAllText("C:/ProgramData/dbg.log", "8");
}
else if (msgid == "savdt")
{
File.WriteAllText("C:/ProgramData/dbg.log", "9");
string[] tnd = rd.Split(',');
var nud = new List<string>();
nud.Add("Player1");
nud.AddRange(tnd);
File.WriteAllText("C:/ProgramData/dbg.log", "A");
string name = nud[0];
string streetname = nud[1];
int money = Convert.ToInt32(nud[2]);
int bounty = Convert.ToInt32(nud[3]);
int playerrep = Convert.ToInt32(nud[4]);
File.WriteAllText("C:/ProgramData/dbg.log", "B");
int rep = Convert.ToInt32(nud[5]);
string pclass = nud[6];
bool canbecop = Convert.ToBoolean(nud[7]);
int rank = Convert.ToInt32(nud[8]);
int stars = Convert.ToInt32(nud[9]);
int cites = Convert.ToInt32(nud[10]);
File.WriteAllText("C:/ProgramData/dbg.log", "C");
int citesgiven = Convert.ToInt32(nud[11]);
int citesdismissed = Convert.ToInt32(nud[12]);
int arrestsmade = Convert.ToInt32(nud[13]);
int arrested = Convert.ToInt32(nud[14]);
int convictionsmade = Convert.ToInt32(nud[15]);
int convitced = Convert.ToInt32(nud[16]);
string warrant = nud[17];
File.WriteAllText("C:/ProgramData/dbg.log", "D");
int prisontimeremaining = Convert.ToInt32(nud[18]);
int copskilled = Convert.ToInt32(nud[19]);
int crimskilled = Convert.ToInt32(nud[20]);
int civskilled = Convert.ToInt32(nud[21]);
int bountyclaimed = Convert.ToInt32(nud[22]);
int overflowprep = Convert.ToInt32(nud[23]);
string title = nud[24];
bool banned = Convert.ToBoolean(nud[25]);
bool vip = Convert.ToBoolean(nud[26]);
int viprank = Convert.ToInt32(nud[27]);
File.WriteAllText("C:/ProgramData/dbg.log", "E");
var v3 = new Vector3();
float posx = Convert.ToSingle(nud[29]);
float posy = Convert.ToSingle(nud[30]);
float posz = Convert.ToSingle(nud[31]);
v3.X = posx;
v3.Y = posy;
v3.Z = posz;
File.WriteAllText("C:/ProgramData/dbg.log", "EE");
int rot = Convert.ToInt32(nud[32]);
File.WriteAllText("C:/ProgramData/dbg.log", "FF");
World.TeleportLocalPlayer(v3, false);
File.WriteAllText("C:/ProgramData/dbg.log", "F");
string custommessage = nud[28];
if (custommessage == "null")
{
} else {
Game.DisplayNotification(custommessage);
}
}
else if (msgid == "isalv")
{
kad = new Byte[26];
kad = Encoding.ASCII.GetBytes("yesil00000" + nd);
conn.Write(kad, 0, kad.Length);
}
else if (msgid == "pospk")
{
}
else
{
Game.DisplayNotification("Unknown packet recieved! ID: " + msgid);
}
//send end client turn
td = new Byte[26];
td = Encoding.ASCII.GetBytes("endmt00000" + nd);
conn.Write(td, 0,td.Length);
File.WriteAllText("C:/ProgramData/dbg.log", "0");
//
}
catch (Exception e)
{
Game.DisplayHelp(Convert.ToString(e));
Game.DisplayNotification("LSPDFR Online has crashed. Try reloading it maybe..?");
}
}
} catch (Exception e) {
Game.DisplayHelp(Convert.ToString(e));
Game.DisplayNotification("Connection interrupted! Reconnecting....");
IsDead = 1;
return;
}
}
}
}
协议就是这样;
Client -> Server: LoginRequest
Server -> Client: LoginOkay
Client -> Server: EndTurnMessage
Server -> Client: SaveDataMessage
Client -> Server: EndTurnMessage
Server -> Client: PositionUpdatePacket
Client -> Server: EndTurnMessage
然后继续例程,但是,服务器只接收这些EndTurnMessage
个数据包中的一个,这意味着它在保存数据部分上窒息,对吗?
可能,但那是在没有缺陷的早期工作,并且从那时起就没有被修改过。
这是一个类文件,因此无法进行调试,而且我一直在撕扯我的头发是什么原因造成的。
是的,它是垃圾代码,需要在某些时候重写,我知道,但是在我完全重写之前我还是喜欢它。
TL; DR:为什么此代码会引发访问冲突?它位于savdt
部门或之后。
更新:我修复了第一个答案中发布的问题,然而,这并没有做太多,所以,正如答案和评论中所发表的那样,它是相当的很难用程序调试,所以我会尝试每一行代码的旧式日志信息路径。我会保持更新。
更新2:我从日志调试中发现导致错误的行是World.TeleportLocalPlayer(v3, false);
。不幸的是,World
无法继承,文档声称Vector3
要求您使用get和set设置其内部值。我之前在MSDN上看到过,但不知道如何搜索它,并且该get
对象中还有set
或Vector3
方法可用。
答案 0 :(得分:1)
您可能有一个保持打开的流,这会阻止创建一个新流。如果msgid是“ConOK”,那么在写操作完成后,您将创建一个新实例而不关闭它。
if (msgid == "ConOK"){
string userid = rd.Substring(0, 16);
Game.DisplayHelp(rd.Substring(16, (rd.Length - 16)));
FileStream savedat = File.OpenWrite(("C:/ProgramData/save.dat"));
BinaryWriter savdat = new BinaryWriter(savedat);
savdat.Write(userid);
// Close file stream here
}
但这只是第一次猜测。您可以通过使用调试器来帮助我们和您自己。您的代码包含在“类文件”中的事实不是问题,而是一个要求。
Hava看看这篇文章,了解有关在C#世界中进行调试的更多信息: http://www.dotnetperls.com/debugging
答案 1 :(得分:1)
乍一看,你可以有不同类别的错误。忽略程序的逻辑流程和预期行为,让我们从基本调试开始。
在这一步,不要使用线程和光纤,从Main只需调用Run
没有强大的输入验证
使用更多的try catch,隔离一小段代码
,打印ex.Message和ex.StackTrace
仔细阅读有关您所调用方法的文档及其可能的例外情况
你在异常(catch)中写一个文件很奇怪
全局变量的可能竞争条件? 在Run中设置IsDead使用Interlocked.Increment https://msdn.microsoft.com/en-us/library/dd78zt0c(v=vs.110).aspx
...