Socket 多连接时发送数据被冲掉怎么办?

风吹裤衩轻飞扬丶 2018-03-21 02:19:56
我有个Socket连接的小程序。每天晚上12点客户端与服务器连接发送数据。但是好像在同一秒连接的太多。然后上一条的数据还没插到数据库里后面的就进来把前面的数据冲掉了。
这个要怎么处理。

private void recv(object socketclientpara)
{
Socket socketServer = socketclientpara as Socket;
socketServer.ReceiveTimeout = 300000; //设置超时时间60S,超时未收到数据则自动退出线程
while (true)
{
//创建一个内存缓冲区 其大小为1024*1024字节 即1M
byte[] arrServerRecMsg = new byte[1024 * 1024];
//将接收到的信息存入到内存缓冲区,并返回其字节数组的长度
try
{
int length = socketServer.Receive(arrServerRecMsg);

if (length<=0)
{
textBox3.AppendText("客户端" + socketServer.RemoteEndPoint + "已经中断连接" + "\r\n"); //提示套接字监听异常
listBoxOnlineList.Items.Remove(socketServer.RemoteEndPoint.ToString());//从listbox中移除断开连接的客户端
socketServer.Close();//关闭之前accept出来的和客户端进行通信的套接字
break;
//throw new Exception();
}

//将机器接受到的字节数组转换为人可以读懂的字符串
string strSRecMsg = Encoding.UTF8.GetString(arrServerRecMsg, 0, length);

if (strSRecMsg.Length > 0)
{
//将发送的字符串信息附加到文本框txtMsg上
textBox3.AppendText("客户端:" + socketServer.RemoteEndPoint + ",时间:" + GetCurrentTime() + "\r\n" + strSRecMsg + "\r\n\n");
}


//插入数据库的一系列操作并回复信息操作

//写入日志
string errors="";
bool aa = WriteFile(strSRecMsg, out errors);

}
catch (Exception ex)
{
if (ex.Message.ToString() != "您的主机中的软件中止了一个已建立的连接。" && ex.Message.ToString().Length != 45)
{
textBox3.AppendText("客户端" + socketServer.RemoteEndPoint + "已经中断连接" + "\r\n"); //提示套接字监听异常
listBoxOnlineList.Items.Remove(socketServer.RemoteEndPoint.ToString());//从listbox中移除断开连接的客户端
socketServer.Close();//关闭之前accept出来的和客户端进行通信的套接字
break;
}

}
}


}





然后现在问题是日志写了。但是数据没存储到数据库里。这个怎么修改?
插入数据库就是用的常见的sql类。
...全文
622 29 打赏 收藏 转发到动态 举报
写回复
用AI写文章
29 条回复
切换为时间正序
请发表友善的回复…
发表回复
jwb7832007 2018-03-24
  • 打赏
  • 举报
回复
在while监听里写数据库,还是这么大的缓冲区,就没考虑过操作时间的问题么。从最开始学习socket的时候第一本能反应就是监听里不能处理耗时过长的具体事务 而且这么大的数据量,自己写socket处理粘包和分包组包了嘛。 如果是为了完成工作建议用现成的库,supersocket或者DotNetty都可以,都有现成的 而如果想学习的话,可以先按他们说的,把数据保存到列表里,另开一个线程循环读取列表数据写出、清除列表(过于频繁读写可能还要加锁) 另外你的while里建议加个Thread.Sleep(xxx);可以降低cpu占用
  • 打赏
  • 举报
回复
引用 27 楼 xuzuning 的回复:
socket 是点对点通讯,如果两个客户端同时请求的话,就必然有两个 recv 方法在同时执行 于是 recv 方法就必须是可重入的(不缓存中间结果,不依赖外部资源) 看到你有回复中提到 dt需要new一下,但你的代码中并没有这个 dt 的定义。如果 这个 dt 是全局的,那么极有可能是问题的原因
那意思是如果有两个客户端同时连接。那就后连接的可能会把先连接的recv方法里的变量给冲掉。是这个意思吗? 我说的那个dt是打比喻。感觉跟那个情况有点一样。就是定义一个dt但是没有new一下。同时两个地方调用这个dt。那后调用的可能会把先调用的dt里的数据给冲掉变成后调用的数据。并不是像new一下那样。不管先后数据不会冲突不会覆盖。
xuzuning 2018-03-24
  • 打赏
  • 举报
回复
socket 是点对点通讯,如果两个客户端同时请求的话,就必然有两个 recv 方法在同时执行 于是 recv 方法就必须是可重入的(不缓存中间结果,不依赖外部资源) 看到你有回复中提到 dt需要new一下,但你的代码中并没有这个 dt 的定义。如果 这个 dt 是全局的,那么极有可能是问题的原因
  • 打赏
  • 举报
回复
是因为连接数据库过于频繁?才导致慢的?
  • 打赏
  • 举报
回复
引用 23 楼 xuzuning 的回复:
如果你的日志记录没有问题的话,那么问题是出在数据库操作那块 但你并没有贴出相关的代码
引用 23 楼 xuzuning 的回复:
如果你的日志记录没有问题的话,那么问题是出在数据库操作那块 但你并没有贴出相关的代码

string MeterNum = "";
                    if (strSRecMsg.Length >= 48)
                    {
                        MeterNum = strSRecMsg.Substring(2, 8);
                        string ip = socketServer.RemoteEndPoint.ToString();

                        //更改数据库连接记录
//先从数据库读取是否有此客户端的连接。如果没有则插入如果有则修改。
                        UpdateWebIP(MeterNum, ip);

                        //判断是否为上传数据
                        string State = strSRecMsg.Substring(10, 2);
                        if (State == "0")//判断是否为回复状态
                        {
                            #region 命令发送情况状态判断
                            string State_Send = strSRecMsg.Substring(12, 2);
                            if (State_Send == "01")//接收成功
                            {

                                //break;
                            }
                            else if (State_Send == "02")//数据格式错误
                            {

                                //break;
                            }
                            else if (State_Send == "03")//断开连接
                            {

                                //更改发送命令的状态为可发送
                               string SQL = "update ";
            int Num = SqlHelper.ExecuteSql(SQL);
                            }
                            #endregion
                        }
                        else if (State == "01" || State == "02" || State == "03" || State == "04" || State == "06")
                        {

                            #region 一般处理情况直接插入

                            #region 判断是否为命令回复,若是则修改数据库命令
                            if (State == "04")
                            {
                                string UploadState = "";
                                string SqlUpdate = "";
                                string Stares = strSRecMsg.Substring(12, 2).ToString();
                                byte SomeOneState_Upload = Convert.ToByte(Stares, 16);
                                if ((SomeOneState_Upload & 0x01) == 0x01)
                                {
                                    UploadState = "2";
                                }
                                if ((SomeOneState_Upload & 0x02) == 0x02)
                                {
                                    UploadState = "4";
                                }
                                if ((SomeOneState_Upload & 0x04) == 0x04)
                                {
                                    UploadState = "9";
                                }
                                if ((SomeOneState_Upload & 0x08) == 0x08)
                                {
                                    UploadState = "5";
                                }
                                if ((SomeOneState_Upload & 0x10) == 0x10)
                                {
                                    UploadState = "0','1','3','7','8";
                                }
                                if ((SomeOneState_Upload & 0x20) == 0x20)
                                {
                                    UploadState = "10";
                                }
                                //修改数据库命令状态
                                SqlUpdate = "update ";
                                SqlHelper.ExecuteSql(SqlUpdate);

                            }
                            #endregion

                            #region 插入数据并回复状态
                            //插入接收数据
                            string sendMsg = "";
                            string SQlsend = "insert";
                            int num = SqlHelper.ExecuteSql(SQlsend);
                            if (num > 0)
                            {
                                sendMsg = "DD00010000";
                            }
                            else
                            {
                                sendMsg = "DD00020000";
                            }
                            string ReplyMessage = Localtest.Class.encrypt.GetXor(sendMsg);
                            string NewCon = sendMsg + ReplyMessage + "AA";
                            //将要发送的信息转化为字节数组,因为Socket发送数据时是以字节的形式发送的  
                            byte[] bytes = System.Text.Encoding.UTF8.GetBytes(NewCon);
                            //发送数据
                            dic[ip].Send(bytes);

                            //显示在服务端
                            textBox3.AppendText("【" + GetCurrentTime() + "】发送给表:" + MeterNum + "\r\n" + NewCon + "\r\n");
                            #endregion


                            #endregion
                        }

                        //写入日志
                        string errors = "";
                        bool RiZhi = WriteFile(strSRecMsg + "", out errors);
}
  • 打赏
  • 举报
回复
引用 20 楼 sp1234 的回复:
跟 while 循环并没有关系。有的人喜欢纠结字眼儿,而根本不用心去理解设计原理说的是什么,所以标题党重复别人的话而用于自己的目的、并非讲明技术模式。 假设你循环地把变动的数据写到数据库,你怎么写?是 insert 还是 update?如果你 update 不断修改那么当然是会产生你说的问题了。但是你并没有贴出实际的将 strSRecMsg 这个值保存到数据库的代码和设计来,这就是这个帖子的问题了。我们都能猜出你“写日志”是 insert 到文件里边的,但是你的数据库操作怎么写的,从这个帖子谁能看出呢?
我刚又按照你说的去看了下代码。 我判断数据后去更改了下表的连接IP。然后继续判断这条数据是哪种类型。如果是命令回复类型就又修改下命令状态。然后把这条回复消息插入到数据库。就这么多。然后下面就是把上传的这条数据插入到日志。是因为我连接数据库次数太多然后导致的前数据被后数据充掉嘛? 正常的不应该是执行一完了后执行二嘛?现在给我的感觉是1.1还没执行完2已经开始执行了。
xuzuning 2018-03-24
  • 打赏
  • 举报
回复
如果你的日志记录没有问题的话,那么问题是出在数据库操作那块 但你并没有贴出相关的代码
  • 打赏
  • 举报
回复
引用 21 楼 sp1234 的回复:
不管你用什么通讯框架,你都要出了自己的业务需求。那么保存分析结果到数据库的操作是你自己写的代码,不是随便抄来的了。所以不管你用 SuperSocket 或者别的什么,都是一样,都要先把自己应该描述清楚的问题能够描述清楚。
就像帖子顶层说的。就是我日志保存完了但数据库里的数据还没保存。但是日志是在保存数据库后面执行的。所以问题不知道是出在了哪。数据库的操作就是解析数据。判断传过来的数据内容然后根据数据内容解析是哪种上传类型。然后判断完上传类型就开始解析数据。然后插入到数据库。如果是多条记录同时上传的就拼接成多条插入语句然后一下插入到数据库。然后保存日志。不管数据插入成功不成功都保存日志。 现在问题是数据是正确的。他没插入到数据库。我看了下日志就是在同一秒内有两个客户端同时向服务器发送数据导致的。我猜测原因是因为像dt需要new一下那样。上条数据还在执行过程中下条数据已经进来把变量给变化了。
  • 打赏
  • 举报
回复
不管你用什么通讯框架,你都要出了自己的业务需求。那么保存分析结果到数据库的操作是你自己写的代码,不是随便抄来的了。所以不管你用 SuperSocket 或者别的什么,都是一样,都要先把自己应该描述清楚的问题能够描述清楚。
  • 打赏
  • 举报
回复
引用 16 楼 qwe564217192 的回复:
[quote=引用 15 楼 xomix 的回复:] 顺便说一下觉得自己写轮子麻烦有SuperSocket这个轮子,你开发不管服务器端还是客户端都不用管,别人用和你一样不一样的都能通讯。
我想问下。他这个会出现就像socket的那个问题嘛。就是一秒内多个连接。然后上一个连接的插入数据操作还没完下一个已经进来了。 我主要是一点都不懂,所以才会出现那个while监听那个。这还是在网上找的例子然后自己修改的程序- -。[/quote] 跟 while 循环并没有关系。有的人喜欢纠结字眼儿,而根本不用心去理解设计原理说的是什么,所以标题党重复别人的话而用于自己的目的、并非讲明技术模式。 假设你循环地把变动的数据写到数据库,你怎么写?是 insert 还是 update?如果你 update 不断修改那么当然是会产生你说的问题了。但是你并没有贴出实际的将 strSRecMsg 这个值保存到数据库的代码和设计来,这就是这个帖子的问题了。我们都能猜出你“写日志”是 insert 到文件里边的,但是你的数据库操作怎么写的,从这个帖子谁能看出呢?
  • 打赏
  • 举报
回复
你的代码是短连接的(不是长连接的),短连接其实仍然需要处理分包,不能简单地
socketServer.Receive(arrServerRecMsg)
之后就立刻以为收到了完整的消息,而应该累积收到的内容,判断消息结束符号收到(比如说对于 http 协议就是用两个连续的“回车换行”作为消息头和消息体的结束符号)了之后才开始解析内容。 不过你的问题是“保存数据库的结果不对”,可是根本看不到你保存数据库的代码设计啊?你不贴出实际的代码、不描述自己的设计,怎么发现问题呢?
  • 打赏
  • 举报
回复
引用 16 楼 qwe564217192 的回复:
[quote=引用 15 楼 xomix 的回复:] 顺便说一下觉得自己写轮子麻烦有SuperSocket这个轮子,你开发不管服务器端还是客户端都不用管,别人用和你一样不一样的都能通讯。
我想问下。他这个会出现就像socket的那个问题嘛。就是一秒内多个连接。然后上一个连接的插入数据操作还没完下一个已经进来了。 我主要是一点都不懂,所以才会出现那个while监听那个。这还是在网上找的例子然后自己修改的程序- -。[/quote] 不会这个轮子不会粘包。
生财 2018-03-21
  • 打赏
  • 举报
回复
使用一个Queue 将多个连接接收到的数据全部存储起来,打上EndPoint .ToString () 后的标识, 再开另一个线程专门处理这个Queue的数据,
  • 打赏
  • 举报
回复
引用 15 楼 xomix 的回复:
顺便说一下觉得自己写轮子麻烦有SuperSocket这个轮子,你开发不管服务器端还是客户端都不用管,别人用和你一样不一样的都能通讯。
我想问下。他这个会出现就像socket的那个问题嘛。就是一秒内多个连接。然后上一个连接的插入数据操作还没完下一个已经进来了。 我主要是一点都不懂,所以才会出现那个while监听那个。这还是在网上找的例子然后自己修改的程序- -。
  • 打赏
  • 举报
回复
顺便说一下觉得自己写轮子麻烦有SuperSocket这个轮子,你开发不管服务器端还是客户端都不用管,别人用和你一样不一样的都能通讯。
  • 打赏
  • 举报
回复
引用 12 楼 qq_17486399 的回复:
[quote=引用 8 楼 xomix 的回复:] 我觉得今天sp累了,不然他又要过来骂人了。 1、用tcpclient和udpclient,不要直接用while(true)做监听。 2、所谓的分线程、对列等,都是让你把接收到的数据序列化存储在内存或其他位置,然后再另外开一个线程处理数据。 3、我觉得sp今天是累了,不知道你们是不是这么觉得。
你这样说sp合适吗?[/quote] 他在看到while 的socket的时候总是那么激动。
  • 打赏
  • 举报
回复
好吧我错了,文章还是while循环的 给msdn吧: https://msdn.microsoft.com/zh-cn/library/system.net.sockets.tcplistener(v=vs.110).aspx 着重看四个异步方法。
大鱼> 2018-03-21
  • 打赏
  • 举报
回复
还有你需要对队列数据量进行控制与判断,防止程序出现异常后队列不断增加,也需要对队列进行备份操作,防止程序死掉后队列里面的消息丢失,备份操作可以使用SQLite,文本文件保存到本地就行。
大鱼> 2018-03-21
  • 打赏
  • 举报
回复
引用 8 楼 xomix 的回复:
我觉得今天sp累了,不然他又要过来骂人了。 1、用tcpclient和udpclient,不要直接用while(true)做监听。 2、所谓的分线程、对列等,都是让你把接收到的数据序列化存储在内存或其他位置,然后再另外开一个线程处理数据。 3、我觉得sp今天是累了,不知道你们是不是这么觉得。
你这样说sp合适吗?
  • 打赏
  • 举报
回复
http://blog.csdn.net/qq_28352753/article/details/51031199 顺手放一下文章解救懒得百度的人
加载更多回复(9)

110,536

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧