读书人

C# Socket udp 本地通讯一直正常 发布

发布时间: 2012-08-30 09:55:54 作者: rapoo

C# Socket udp 本地通信一直正常 发布到公网后 就只有第一次数据收发正常
具体情况是这样。

我在本机 开服务端 和客户端 客户端无论何时发送消息 服务端在回给客户端确认消息 都是正常的。

但是我把服务端 发布在公网,我 第一次 发送消息给客户端 服务端 立马 能回消息给客户端,但是 假设我这个时候客户端什么都不做,等过 个 5 6 分钟在去发送消息给服务端,服务端 能接收到消息,可是服务端回给客户端的确认消息 客户端就接收不到了。
客户端程序每4分钟 会发个 心跳包给服务端。

如果不停发送消息 服务端回的消息还是能接到的,就是不能停顿,停个几分钟感觉 socket 就收不到消息.



这个问题 困扰我N久了 实在找不到原因 才发帖求助 ,求做过类似功能的朋友 帮忙解答下。
下面上代码.


客户端

C# code
 try            {                byte[] data = new byte[1024];                string msg;                //构建UDP服务器                // Console.WriteLine("This is a Client, host name is {0}", Dns.GetHostName());                //设置服务IP,设置UDP端口号                //定义网络类型,数据连接类型和网络协议UDP                                string welcome = "L" + UserHelper.loginUser.id.ToString();                data = Encoding.UTF8.GetBytes(welcome);                sokClient.SendTo(data, data.Length, SocketFlags.None, ipep);                byte[] arrMsg2 = System.Text.Encoding.UTF8.GetBytes("H"+UserHelper.loginUser.id.ToString());                sokClient.SendTo(arrMsg2, arrMsg2.Length, SocketFlags.None,ipep);                IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);                EndPoint Remote = (EndPoint)sender;                data = new byte[1024];                //对于不存在的IP地址,加入此行代码后,可以在指定时间内解除阻塞模式限制                //server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 100);                int recv = sokClient.ReceiveFrom(data, ref Remote);                Console.WriteLine(" from {0}: ", Remote.ToString());                Console.WriteLine(Encoding.UTF8.GetString(data, 0, recv));                                while (true)                {                    //server.SendTo(Encoding.UTF8.GetBytes("ok"), Remote);                    data = new byte[1024];                    recv = sokClient.ReceiveFrom(data, ref Remote);                    msg = Encoding.UTF8.GetString(data, 0, recv);                    if (msg.Length > 0)                    {                        string headCommand = msg.Substring(0, 1);                        switch (headCommand)                        {                            case "N":                                string content = msg.Substring(1);                                //MsgNewsForm mnf = new MsgNewsForm(content);                              //  MsgPresentationManage.GetInstance().AddMsgNewsForm(mnf);                                MessageBox.Show(msg);                                break;                            case "M":                                string sendUserId = msg.Substring(1);                                OAUsers user = userBLL.GetModel(int.Parse(sendUserId));                                UserHelper.SendUserName = user.userName;                                timerSend.Enabled = true;                                timerSend.Start();                                notifyIcon1.Icon = PPSoft.Properties.Resources._1;                                break;                            case "H":                                string heartUserId = msg.Substring(1);                                Console.WriteLine(heartUserId + "发来的心跳包");                                break;                            default: break;                        }                    }                    Console.WriteLine(msg);                }            }            catch (Exception ex)            {                                           }




服务端:
C# code
 int recv;            byte[] data = new byte[1024];            //构建UDP服务器            //得到本机IP,设置UDP端口号                     IPEndPoint ipep = new IPEndPoint(IPAddress.Any, 8001);            Socket newsock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);            //绑定网络地址            newsock.Bind(ipep);           // Console.WriteLine("This is a Server, host name is {0}", Dns.GetHostName());            //等待客户机连接            Console.WriteLine("等待客户端连接...");            //得到客户机IP            IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);            EndPoint Remote = (EndPoint)(sender);             while (true)            {                data = new byte[1024];                //发送接受信息                recv = newsock.ReceiveFrom(data, ref Remote);                Console.WriteLine(Encoding.UTF8.GetString(data, 0, recv));                string msg = Encoding.UTF8.GetString(data, 0, recv);                try                {                    if (msg.Length > 0)                    {                                              string headCommand = msg.Substring(0, 1);                        switch (headCommand)                        {                            case "A":                                //心跳包                                                                                                Console.WriteLine("心跳包:" + msg);                               // string heartUserId = msg.Substring(1);                               // byte[] heartNews = Encoding.UTF8.GetBytes("H" + heartUserId);                                //newsock.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1);                                //foreach (string uId in userIps.Keys)                                //{                                //    newsock.SendTo(heartNews, heartNews.Length, SocketFlags.None, userIps[uId]);                               // }                                                                break;                            case "H":                                //心跳包                                                                string heartUserId = msg.Substring(1);                                byte[] heartNews = Encoding.UTF8.GetBytes("H" + heartUserId);                                newsock.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1);                                foreach (string uId in userIps.Keys)                                {                                    newsock.SendTo(heartNews, heartNews.Length, SocketFlags.None, userIps[uId]);                                }                                break;                            case "L":                                Console.WriteLine("客户端请求-来自: {0}: ", Remote.ToString());                                Console.WriteLine(msg);                                string userId = msg.Substring(1);                                if (!userIps.ContainsKey(userId))                                {                                    userIps.Add(userId, Remote);                                }                                else                                {                                    userIps[userId] = Remote;                                }                                break;                             //发布新闻                            case "N":                                string content = msg.Substring(1);                                byte[] returnNews = Encoding.UTF8.GetBytes("N"+content);                                newsock.SetSocketOption(SocketOptionLevel.Socket,SocketOptionName.Broadcast, 1);                                                                 foreach (string uId in userIps.Keys)                                {                                    newsock.SendTo(returnNews, returnNews.Length, SocketFlags.None, userIps[uId]);                                }                                                                break;                            case "M":                                Console.WriteLine(msg);                                int index = msg.IndexOf("#");                                string sendUserId = msg.Substring(1, index - 1);                                string sendUserIds = msg.Substring(index + 1);                                byte[] returnMsg = Encoding.UTF8.GetBytes("M" + sendUserId);                                newsock.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1);                                foreach (string sendId in sendUserIds.Split(','))                                {                                    if (sendId != "")                                    {                                        if (userIps.ContainsKey(sendId))                                        {                                            newsock.SendTo(returnMsg, returnMsg.Length, SocketFlags.None, userIps[sendId]);                                        }                                    }                                }                                break;                            default: break;                        }                    }                                   }                catch (Exception ex)                {                    Console.WriteLine(ex.Message);                }            } 



[解决办法]
需要打洞,因为公网上的服务器端找不到你所在局域网内的客户端。

1:只有客户端主动发消息给服务器端服务器端返回的消息才能正确接收到
2:如果客户端主动发消息,这个时候路由器会做一个映射,而这个映射在一段时间之后就会释放,所以才会出现你说的一旦停个几分钟客户端不主动发消息,服务器端发消息给客户端就收不到了,
[解决办法]
公网的服务端不知道你发过来的包应该给到下边具体的哪个ip端口。所以需要打洞。
a想和b通信,则b(服务端下的ip)要先向a的外网发包,这时b的外网那层会有一个洞,这时a再往b的外网发包,b就可以收到了。
这个洞我以前做过实验,一般半分钟就会消失

读书人网 >C#

热点推荐