关于c#的socket,客户端发消息,服务端只接收一次的问题.

风都占用么 2014-01-14 02:56:25

//服务端代码
using ServerDemo.roc.socket_package;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace ServerDemo.windows_package
{
public partial class WindowMain : Form
{
private Socket socket = null;
public WindowMain()
{
InitializeComponent();
}

private void buttonOpen_Click(object sender, EventArgs e)
{
Thread threadListen = new Thread(new ThreadStart(listen));
threadListen.IsBackground = true;
threadListen.Start();

}
private void listen()
{
Console.WriteLine("Start Listening ...");
appendtextBoxLog("Start Listening ...");
Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //基于TCP/IP的网络上通讯;
//Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); //基于UDP的网络上通讯;
serverSocket.Bind(new IPEndPoint(IPAddress.Any, 6666));//设定该套接字的绑定IP,接受从任意IP地址发往端口6666的消息;//如果需要限制IP,就把IPAddress.Any改一下;
serverSocket.Listen(1000);//将套接字设置为监听状态,并设置监听队列为100;//解释:如果1秒内有N多人并发访问可能暂时要存在队列里,估计1秒内几千人访问,设置100就足够用了.
while (true)//死循环,即不发生异常中断的情况下一直接受消息
{
this.socket = serverSocket.Accept();//(4)Create a new Socket for a newly created connection
appendtextBoxLog(this.socket.RemoteEndPoint.ToString()+" 连接成功");
Thread thread = new Thread(new ThreadStart(start));
thread.IsBackground = true;
thread.Start();
}
}
private void start()
{
SocketThreadClass stc = new SocketThreadClass(this.socket,this.textBoxLog);
}

private void button1_Click(object sender, EventArgs e)
{

}
#region 窗体代码
private void appendtextBoxLog(string msg)
{
textBoxLog.Invoke((MethodInvoker)delegate
{
textBoxLog.AppendText(msg+"\r\n");
});
}
#endregion
}
}
//接收消息的类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Windows.Forms;

namespace ServerDemo.roc.socket_package
{
class SocketThreadClass
{
private Socket socket = null;
private TextBox textBoxLog = null;
public SocketThreadClass(Socket socket,TextBox textBoxLog)
{
this.socket = socket;
this.textBoxLog = textBoxLog;
start();

}
private void start()
{
try
{
while (true)
{
appendtextBoxLog("接收消息中...");
byte[] receiveBytes = new byte[1024];
socket.Receive(receiveBytes);//(4)获取服务器的响应数据;//远程主机强迫关了了一个现有连接异常,会触发
Console.WriteLine(Encoding.ASCII.GetString(receiveBytes));
appendtextBoxLog(Encoding.ASCII.GetString(receiveBytes));
appendtextBoxLog("接受完毕");
}
}
catch (SocketException)//一般是远程主机强制关闭连接引发的异常.(例如:远程主机强制关闭了,我还在接收数据就引发了;如果远程主机正常关闭,即使我还在接收数据也不会引发异常.)
{
appendtextBoxLog(this.socket.RemoteEndPoint.ToString()+" 远程主机强制关闭连接");
if (socket != null)
{
socket.Shutdown(SocketShutdown.Both);
socket.Close();
}
}
}
#region 窗体代码
private void appendtextBoxLog(string msg)
{
textBoxLog.Invoke((MethodInvoker)delegate
{
this.textBoxLog.AppendText(msg + "\r\n");
});
}
#endregion
}
}
//客户端代码
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Windows.Forms;

namespace ClientDemo.windows_package
{
public partial class WindowMain : Form
{
private Socket clientSocket = null;
public WindowMain()
{
InitializeComponent();
}

private void buttonConnection_Click(object sender, EventArgs e)
{
clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//(1)首先在服务器端定义一个套接字(socket),使用Tcp协议
//IPHostEntry ipHost = Dns.GetHostEntry("threadroc.xicp.net");//可以是域名也可以是IP地址;//还是说只能是域名?
//IPAddress ipAddress = ipHost.AddressList[0];
IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
IPEndPoint ipEndPoint = new IPEndPoint(ipAddress, 6666);
try
{
clientSocket.Connect(ipEndPoint);//(2)其次设定该套接字的链接IP,发送到指定IP地址的6666端
}
catch(SocketException)
{
Console.WriteLine("连接失败");
}

//byte[] receiveBytes = new byte[1024];
//Console.WriteLine("----------------");
//clientSocket.Receive(receiveBytes);//(4)获取服务器的响应数据
//Console.WriteLine("----------------");
//Console.WriteLine("received from server: " + Encoding.ASCII.GetString(receiveBytes));
}

private void buttonSend_Click(object sender, EventArgs e)
{
string str = "hello, the socket test1";
byte[] sendBytes = Encoding.ASCII.GetBytes(str);
clientSocket.Send(sendBytes);//(3)发送数据比特流
}

private void buttonClose_Click(object sender, EventArgs e)
{
clientSocket.Shutdown(SocketShutdown.Both);//(5)Disables sends and receives on a System.Net.Sockets.Socket
clientSocket.Close();//(6)关闭socket Connection,释放所有已占用资源
}
}
}




以上就是全部代码了

但是我遇到的问题是,服务器只要点击开启按钮后,然后客户端连接,点击发送按钮发消息
服务器会收到;再然后客户端不管怎么点击发送按钮向服务器发送消息,服务器都收不到消息了.
即使客户端关闭程序,断开连接,重新连接上,点击发送按你,服务器还是收不到消息
这问题困扰我7个小时54分钟32.34秒了,希望大神灭了这孽障.
小弟在此不胜感激.
将来我若成为亿万富翁,必有后报.
...全文
1934 24 打赏 收藏 转发到动态 举报
写回复
用AI写文章
24 条回复
切换为时间正序
请发表友善的回复…
发表回复
tunhuyuan6487 2016-09-18
  • 打赏
  • 举报
回复
写的啥啊。。。。乱遭的。。。
魂之挽歌来袭 2014-01-14
  • 打赏
  • 举报
回复
引用 22 楼 qldsrx 的回复:
我怎么感觉那个代码的设计思路也存在严重的问题啊,仔细看了下那个SocketThreadClass类,如果正常情况下是永远不会被初始化完毕的,这个本身就是大问题了,因为对象没初始化完,那么就得不到该对象的正常引用,GC就能认为该对象没有引用可以回收。
是的 我也觉得 他在初始化的时候 一直在用while循环接受客户端发送过来的消息
qldsrx 2014-01-14
  • 打赏
  • 举报
回复
我怎么感觉那个代码的设计思路也存在严重的问题啊,仔细看了下那个SocketThreadClass类,如果正常情况下是永远不会被初始化完毕的,这个本身就是大问题了,因为对象没初始化完,那么就得不到该对象的正常引用,GC就能认为该对象没有引用可以回收。
魂之挽歌来袭 2014-01-14
  • 打赏
  • 举报
回复
引用 20 楼 qldsrx 的回复:
肯定不是Socket对象引用丢弃或张冠李戴的问题,这里使用完全是安全的,看这段代码: private void start() { SocketThreadClass stc = new SocketThreadClass(this.socket,this.textBoxLog); } 即使重用this.socket这个变量,实际数据接收是在一个私有类里面,因此那个外部的变量如何被重用都无关紧要了。 但是再仔细看这个start方法,存在一个很容易被忽略的错误,那就是对象的作用域范围,这个函数执行完毕后,这个stc 临时对象离开了那个作用域就直接可以被GC回收了,既然对象可以被回收,那么对象内部再执行的数据接收方法自然就没戏了。你通过对象来封装处理,就要保持对象引用以免被GC回收才行。 PS:都没解决问题居然结贴了,我要是不负责的话,可以不回复了。
你这里离开作用域 应该是start执行完之后吧 而start执行完之后 客户端发送过来的消息已经接收完毕 这个stc确实没啥意义了啊(在楼主上面的代码中) 所以 应该不是这个问题
qldsrx 2014-01-14
  • 打赏
  • 举报
回复
肯定不是Socket对象引用丢弃或张冠李戴的问题,这里使用完全是安全的,看这段代码: private void start() { SocketThreadClass stc = new SocketThreadClass(this.socket,this.textBoxLog); } 即使重用this.socket这个变量,实际数据接收是在一个私有类里面,因此那个外部的变量如何被重用都无关紧要了。 但是再仔细看这个start方法,存在一个很容易被忽略的错误,那就是对象的作用域范围,这个函数执行完毕后,这个stc 临时对象离开了那个作用域就直接可以被GC回收了,既然对象可以被回收,那么对象内部再执行的数据接收方法自然就没戏了。你通过对象来封装处理,就要保持对象引用以免被GC回收才行。 PS:都没解决问题居然结贴了,我要是不负责的话,可以不回复了。
魂之挽歌来袭 2014-01-14
  • 打赏
  • 举报
回复
引用 17 楼 wenyu_825 的回复:
[quote=引用 15 楼 kxm_2012 的回复:] [quote=引用 10 楼 wenyu_825 的回复:] [quote=引用 5 楼 kxm_2012 的回复:] 你这里肯定是有问题的 socket服务端的套接字至少有两个 一个是监听是否有客户端连接用的 当有客户端连接的时候 调用开始监听套接字的Accpet方法会返回一个专门负责和客户端通信的套接字 而这个套接字才是负责通信的 而不是用监听套接字和客户端通信。
不过这位大婶,刚次看另一位大婶给的启发,突然发现问题所在了,我在循环里每次循环会创建一个新的ServerSocket,就造成这种后果了,应该是第一次创建的serverSocket把之后创建的ServerSocket端口阻塞了,谢谢大婶.[/quote] 其实 你可以把服务端的监听套接字声明为服务端类的一个私有变量而不是把客户端的通信套接字声明为私有变量 [/quote] 那个,刚才理解错了,貌似问题还是没解决,服务器那个Socket的确只创建了一个,客户端的请求进来的Socket还是只能接受第一次发的消息,第二次就不行了....[/quote] 你把你的serverSoeket 放在启动按钮的事件里面创建 不要放在监听线程里面创建 试试
风都占用么 2014-01-14
  • 打赏
  • 举报
回复
引用 8 楼 sp1234 的回复:
别的乱七八糟的都不值得讨论了,仅说最成问题的: 每一次执行 serverSocket.Accept() 都返回了一个新的 socket 对象实例,你怎么能把之前的 this.socket 变量所引用的丢掉、让它引用新的对象呢?如果这样,别的地方使用 this.socket 变量一定会张冠李戴。
那个,可是我服务器为何还是只接收一次客户端发送来的消息呢.... 指的是客户端连接服务器成功以后,客户端不管发送多少消息,服务器那边只接收第一次发来的消息...
风都占用么 2014-01-14
  • 打赏
  • 举报
回复
引用 15 楼 kxm_2012 的回复:
[quote=引用 10 楼 wenyu_825 的回复:] [quote=引用 5 楼 kxm_2012 的回复:] 你这里肯定是有问题的 socket服务端的套接字至少有两个 一个是监听是否有客户端连接用的 当有客户端连接的时候 调用开始监听套接字的Accpet方法会返回一个专门负责和客户端通信的套接字 而这个套接字才是负责通信的 而不是用监听套接字和客户端通信。
不过这位大婶,刚次看另一位大婶给的启发,突然发现问题所在了,我在循环里每次循环会创建一个新的ServerSocket,就造成这种后果了,应该是第一次创建的serverSocket把之后创建的ServerSocket端口阻塞了,谢谢大婶.[/quote] 其实 你可以把服务端的监听套接字声明为服务端类的一个私有变量而不是把客户端的通信套接字声明为私有变量 [/quote] 那个,刚才理解错了,貌似问题还是没解决,服务器那个Socket的确只创建了一个,客户端的请求进来的Socket还是只能接受第一次发的消息,第二次就不行了....
风都占用么 2014-01-14
  • 打赏
  • 举报
回复
引用 12 楼 sp1234 的回复:
说句题外话: 在.net中的程序,不要总是抄袭低级的java代码。在.net中有很多高级得多的机制,例如简洁高效的异步处理,有天然支持IOCP的TcpListener,等等。 请学习.net程序设计。如果你的培训班老师只会从java代码移植一些过来,那么请你另外聘请一位真正精通.net的。
嗯嗯,谢谢指教
魂之挽歌来袭 2014-01-14
  • 打赏
  • 举报
回复
引用 10 楼 wenyu_825 的回复:
[quote=引用 5 楼 kxm_2012 的回复:] 你这里肯定是有问题的 socket服务端的套接字至少有两个 一个是监听是否有客户端连接用的 当有客户端连接的时候 调用开始监听套接字的Accpet方法会返回一个专门负责和客户端通信的套接字 而这个套接字才是负责通信的 而不是用监听套接字和客户端通信。
不过这位大婶,刚次看另一位大婶给的启发,突然发现问题所在了,我在循环里每次循环会创建一个新的ServerSocket,就造成这种后果了,应该是第一次创建的serverSocket把之后创建的ServerSocket端口阻塞了,谢谢大婶.[/quote] 其实 你可以把服务端的监听套接字声明为服务端类的一个私有变量而不是把客户端的通信套接字声明为私有变量
魂之挽歌来袭 2014-01-14
  • 打赏
  • 举报
回复
引用 8 楼 sp1234 的回复:
别的乱七八糟的都不值得讨论了,仅说最成问题的: 每一次执行 serverSocket.Accept() 都返回了一个新的 socket 对象实例,你怎么能把之前的 this.socket 变量所引用的丢掉、让它引用新的对象呢?如果这样,别的地方使用 this.socket 变量一定会张冠李戴。
后来看来看你的代码 觉得这个大神说的有道理 没一个客户端连接 都会创建一个不同的通信套接字 你应该声明一个集合来存这些通信套接字 而不是来了一个客户端连接 就赋值给this.socket 这样 最后可定会乱的。
风都占用么 2014-01-14
  • 打赏
  • 举报
回复
引用 8 楼 sp1234 的回复:
别的乱七八糟的都不值得讨论了,仅说最成问题的: 每一次执行 serverSocket.Accept() 都返回了一个新的 socket 对象实例,你怎么能把之前的 this.socket 变量所引用的丢掉、让它引用新的对象呢?如果这样,别的地方使用 this.socket 变量一定会张冠李戴。
这位大神,您仔细看看代码,其实,客户端请求的Socket搞到另一个类里以后,所以这个Socket引用也就没用了,但是根据您的启发,我突然发信我把aceept的服务器主ServerSocket放到循环里了,每次都会新创建一个服务器ServerSocket,所以第一次创建的accept的socket就把后面创建的端口给堵塞了.我是这样理解的. 谢谢大神的指教
  • 打赏
  • 举报
回复
说句题外话: 在.net中的程序,不要总是抄袭低级的java代码。在.net中有很多高级得多的机制,例如简洁高效的异步处理,有天然支持IOCP的TcpListener,等等。 请学习.net程序设计。如果你的培训班老师只会从java代码移植一些过来,那么请你另外聘请一位真正精通.net的。
魂之挽歌来袭 2014-01-14
  • 打赏
  • 举报
回复
引用 9 楼 wenyu_825 的回复:
[quote=引用 5 楼 kxm_2012 的回复:] 你这里肯定是有问题的 socket服务端的套接字至少有两个 一个是监听是否有客户端连接用的 当有客户端连接的时候 调用开始监听套接字的Accpet方法会返回一个专门负责和客户端通信的套接字 而这个套接字才是负责通信的 而不是用监听套接字和客户端通信。
这位大神,其实我是有2个的,你可能每注意,一个是serverSocket 一个和socket[/quote] 哦哦 是有两个 没注意 那你就打断点调试吧 看看问题出在那里
风都占用么 2014-01-14
  • 打赏
  • 举报
回复
引用 5 楼 kxm_2012 的回复:
你这里肯定是有问题的 socket服务端的套接字至少有两个 一个是监听是否有客户端连接用的 当有客户端连接的时候 调用开始监听套接字的Accpet方法会返回一个专门负责和客户端通信的套接字 而这个套接字才是负责通信的 而不是用监听套接字和客户端通信。
不过这位大婶,刚次看另一位大婶给的启发,突然发现问题所在了,我在循环里每次循环会创建一个新的ServerSocket,就造成这种后果了,应该是第一次创建的serverSocket把之后创建的ServerSocket端口阻塞了,谢谢大婶.
风都占用么 2014-01-14
  • 打赏
  • 举报
回复
引用 5 楼 kxm_2012 的回复:
你这里肯定是有问题的 socket服务端的套接字至少有两个 一个是监听是否有客户端连接用的 当有客户端连接的时候 调用开始监听套接字的Accpet方法会返回一个专门负责和客户端通信的套接字 而这个套接字才是负责通信的 而不是用监听套接字和客户端通信。
这位大神,其实我是有2个的,你可能每注意,一个是serverSocket 一个和socket
  • 打赏
  • 举报
回复
别的乱七八糟的都不值得讨论了,仅说最成问题的: 每一次执行 serverSocket.Accept() 都返回了一个新的 socket 对象实例,你怎么能把之前的 this.socket 变量所引用的丢掉、让它引用新的对象呢?如果这样,别的地方使用 this.socket 变量一定会张冠李戴。
Regan-lin 2014-01-14
  • 打赏
  • 举报
回复
http://bbs.csdn.net/topics/390597369 看下里面的那个例子
Regan-lin 2014-01-14
  • 打赏
  • 举报
回复
http://bbs.csdn.net/topics/390513919?page=1#post-394999829 是不是你的原因
魂之挽歌来袭 2014-01-14
  • 打赏
  • 举报
回复
你这里肯定是有问题的 socket服务端的套接字至少有两个 一个是监听是否有客户端连接用的 当有客户端连接的时候 调用开始监听套接字的Accpet方法会返回一个专门负责和客户端通信的套接字 而这个套接字才是负责通信的 而不是用监听套接字和客户端通信。
加载更多回复(4)

110,571

社区成员

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

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

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