string[] splitString = receiveString.Split(','); string sendString = ""; string command = splitString[0].ToLower(); switch (command) { case "g": //格式:gprsLogin,昵称 //GPRS用户刚刚登陆 i = i + 1; Ngprs = Convert.ToString(i); SetLabel(label_GPRS,Ngprs); service.AddItem(string.Format("当前连接GPRS终端数:{0}", i)); service.SendToOne(user, "ok"); for (int j = 0; j < 11; j++) dataStr[j] = dataStr[j+1]; dataStr[11] = splitString[2];
就是这段程序,我发送过去的是“g,GPRS,22\n”的数据第一次程序能够识别进入case语句,但是第二次我发送相同的命令就进不了case语句,这是为什么,很急,采集的数据从GPRS发到服务器的,这段是服务器程序,望大神帮助解决一下,万分感谢
你不会单步看一下command的值吗?
这段代码没问题,肯定是第二次发来的数据 receiveString 格式不对,查查发送数据的代码
发送的数据就是“g,GPRS,22\n”,我在查查
@嗯啊: 那你得查查 逗号对不对 ,g 前后有没有空格
@Yu: 这个没有问题,我在看看
这个应该很好解决吧。单步,确认问题...
我是新手,不太会,我在找找问题
@嗯啊: 在这个方法内部,代码是一句一句跑的。如果不能进入case,那么检查下上面的变量,一下子就能跟踪到原因~
@幻天芒: 因为这是服务器程序,而我在学校,学校路由问题,只能把程序放到服务器上运行。所以我没有办法单步运行,并且数据我是用GPRS模块发的,我身处学校,没办法~~~我其实也想单步运行,
@嗯啊: 没有单步,可以写文件输出,同样能达到测试的效果。
@幻天芒: 好的好的,我试试
@嗯啊: 很多时候,调试技巧比编程技巧更重要。Good luck!
@幻天芒:我不太会,文件输出要怎么写啊
@幻天芒: 谢谢,我去查查
@嗯啊: 定义一个变量string content=string.Empty;来存取内容。然后找个合适的地方,File.WriteAllText(filePath,content);
@幻天芒: 万分感谢
@嗯啊: 非常感谢,用输出文本,已经找到在哪出错了,第二次接受的命令“g”前面出现了一个空格“ g”导致没办法判断,再次谢谢,你的那句话,调试技巧比编程技巧更重要
@嗯啊: 我加了去空格的语句怎么还是不行啊,文本输出显示还是有空格,
string[] splitString = receiveString.Trim().Split(',');
这是为什么 啊
@嗯啊:
string command = splitString[0].ToLower().Trim()
改成这试试
无论如何,你都不该创建一个没有初始值的需要分割的变量,并且没有给它容错,如果你传过来的值是空的,岂不是直接就报错了?
好像就是你说的这个问题,我发过来的是“命令符,用户名,数据”,,那要怎么修改一下,我是新手,希望大神指点一下
@嗯啊: 你在使用参数之前先做判断啊,如果不符合要求,返回错误,return,如果合法,才继续走下去。。。
如果无论参数正误都要继续下文,就先创建一个符合你规范的字符串,然后写进去你的默认值,如果传进来的参数为空的时候就用你的默认值
@焰£天琊:
default: service.SendToAll(userList, "什么意思啊:" + receiveString); break;
你是说的default吗
@嗯啊: 如果需要的话,可以这么加呀
我比较不放心的是这一段
string[] splitString = receiveString.Split(',');
string sendString = "";
string command = splitString[0].ToLower();
建议你把整个方法内部用try/catch包起来,然后把抛出的错误存在某个地方,或者返回客户端,这样就相当于有debug了
@焰£天琊: 哦哦,谢谢,我修改一下试试
@嗯啊: 一群人猜来猜去,结果只是粗心的结果TT,仿佛又看见了当年的自己。。。。
不过调试确实是基本功,一个程序猿有限的生命内几乎都在无限调试啊
前面的代码再发全点
private void ReceiveData(object obj) { User user = (User)obj; TcpClient client = user.client; //是否正常退出接收线程 bool normalExit = false; //用于控制是否退出循环 bool exitWhile = false; while (exitWhile == false) { string receiveString = null; try { receiveString = user.sr.ReadLine(); } catch (Exception ex) { //该客户底层套接字不存在时会出现异常 service.AddItem("接收数据失败,原因:" + ex.Message); } //TcpClient 对象将套接字进行了封装,如果TcpClient对象关闭了, //但是底层套接字未关闭,并不产生异常,但是读取的结果为 null if (receiveString == null) { if (normalExit == false) { //如果停止了监听,Connected 为 false if (client.Connected == true) { service.AddItem(string.Format("与{0}失去联系,已停止接收该用户信息", client.Client.RemoteEndPoint)); } //如果该用户正在游戏桌上,则退出游戏桌 //RemoveClientfromPlayer(user); } //退出循环 break; } //service.AddItem(string.Format("来自{0}:{1}", user.userName, receiveString)); string[] splitString = receiveString.Split(','); string sendString = ""; string command = splitString[0].ToLower(); switch (command) { case "g": //格式:gprsLogin,昵称 //GPRS用户刚刚登陆 i = i + 1; Ngprs = Convert.ToString(i); SetLabel(label_GPRS,Ngprs); service.AddItem(string.Format("当前连接GPRS终端数:{0}", i)); service.SendToOne(user, "ok"); for (int j = 0; j < 11; j++) dataStr[j] = dataStr[j+1]; dataStr[11] = splitString[2]; updatedata++; if (i > maxGPRS) { sendString = "Sorry"; service.SendToOne(user, sendString); service.AddItem("GPRS采集终端数已满,拒绝" + splitString[1] + "联入服务器"); exitWhile = true; } else { /* *将用户昵称保存到用户列表中 *用于是引用类型,因此直接给user赋值也就是给userList中对应的user赋值 *用户名中包含其IP和端口的目的是为了帮助理解,实际游戏中一般不会显示IP的 */ user.userName = string.Format("[{0}--{1}]", splitString[1], client.Client.RemoteEndPoint); //允许该用户进入游戏室,即将各桌是否有人的情况发送给该用户 sendString = "LoginSuccess"; service.SendToOne(user, sendString);
@嗯啊: 是用socket吧?觉得好多代码是多余的,socket也不用这样写
给你个思路:
1、在第一行语句那里设置断点,确认第二次发送命令时是否进入了循环,如果没有命中断点,自然问题在别的地方,另找原因。
2、如果有命中,检查你接收的数据receiveString的内容,是否如你所愿的正确接收到了内容。
你的问题主要原因应该还是在第一点,第二点的可能性较低。
因为这是服务器程序,而我在学校,学校路由问题,只能把程序放到服务器上运行。所以我没有办法单步运行,并且数据我是用GPRS模块发的,我身处学校,没办法~~~
我可能需要在本地模拟一下
@嗯啊: 可以。先在本地模拟,看下结果。
至于服务器,虽然不能通过断点的方式跟踪,但你可以通过把数据写入到数据库、静态文本文件、事务日志等方式来达成目的。
断点跟踪不要拘泥于一定要象本地调试那样设置断点来实现。
@519740105: 受教,上面一哥们也叫我把数据输出到文本,我研究一下怎么输出到文本,感谢
@嗯啊: 写其它的都不方便,输出文本是最简单的。
但是:
1、输出文本要有本地文件系统的创建与修改的权限(指定目录)
2、还要方便你把输出的内容下载到本地进行查看。
使用数据库的话,相对好点,但是要影响数据库系统,这个你自己酌情考虑用哪个方案了。
@519740105: 非常谢谢,已经用输出文本找到问题原因了,第二次的命令字符g前面多了个空格,感谢,我在研究研究怎么把空格去掉
@嗯啊: 如果只是一个空格的问题,你可以对split函数进行技术处理,同时对结果进行意思空格删除的行为。这样你在找发送命令的问题的时候,要轻松很多,毕竟,空格而已。
@519740105: 加了去空格语句还是不行,文本输出命令字符里还是出现了空格
@嗯啊: 那在服务器端进行技术处理。
线程?线程池? 异步了吧。
额~~~~·我新手,能说具体一点吗
string[] splitString = receiveString.Trim().Split(new char[]{','}, StringSplitOptions.RemoveEmptyEntries).Distinct().ToArray()
改成这样吧,去掉空格,去掉重复
改成了你这个,我也试了string[] splitString = receiveString.Trim().Split(',');这个,,,,但是还是不行啊,里面还是有空格
string[] splitString = receiveString.Split(new string[] { ",","," }, StringSplitOptions.RemoveEmptyEntries);
去除空项,断点看看第二次收到的receiveString的数据是什么?看看是不是,与,的问题逐步调试总会找到问题的 Good Luck!
用IO写文件,把接收到的数据写到文件里看看都接收到了什么东西。
我就是用的这种方法发现的从第二次开始接收的命令符前面有个命令符,服务器程序就识别不了了
@嗯啊: 那就看能不能改掉命令符的发送程序,让他不要有命令符,再么就是在接收的时候把这个命令符过滤掉。
TCP通信收到的数据?
是的
@嗯啊: TCP收到的数据可能会发生粘包现象了,所以有时候收到的并不是一条数据,那可能也不是你一次发出去的数据了
@metoer: 已经用文本输出监控到command前面有空格,没别的问题,只是空格,用语句处理不掉
@嗯啊: 既然是空格,那替换掉就可以了啊
@metoer: 我用substring截取掉了,但是总感觉这不是正路
@嗯啊: 用.Replace()这个方法啊
@metoer: 没有意义,和substring差不多,还是没有解决实质问题
@嗯啊: 那看来你还是得找源头,看空格那里来的,不会无缘无故多的
@metoer: 知道它是485收发切换时候出现的,但是消不掉