C# 关于Socket 多线程的Server端 Client端的收发数据

allen3010 2010-05-26 04:55:09
我最近有玩Socket 的多线程的问题
但我的程序逻辑有些问题,我的Server端可以接受多个Client端的连接,并且都能接受他们所发送过来的数据,但只要其中一个Client端断开后,服务器端就接受不了其他Client端发送过来的数据,我知道我的逻辑有问题(后面是我的Server端的部分代码),但我不知道怎么写?请各位大侠指教!谢谢
然后我的Server端需要要向指定的Client端发送数据,这么我怎么才能做的到?(向指定的Client发送指定信息), 请大侠们指教一下,最好有代码,谢谢!

以下是我Server端的部分代码:

//开启线程
public void StartThread()
{

// ClientNumber++;
ServerThread = new Thread(new ThreadStart(RecieveAccept));//将接受客户端连接的方法委托给线程

ServerThread.Start();

CheckForIllegalCrossThreadCalls = false;//不捕获对错误线程的调用

this.SetText("服务于" + DateTime.Now.ToString() + "开始运行");
}

//接受客户端连接的方法和接收数据
private void RecieveAccept()
{


while(true)
{
//ClientNumber++;

ServerSocket.Listen(10);//开始监听,并且挂起数为10

ClientSocket[ClientNumber] = ServerSocket.Accept();

this.StartThread();
ClientSocket[ClientNumber].BeginReceive(msgbuffer, 0, msgbuffer.Length, 0, new AsyncCallback(RecieveCallBack), ClientSocket[ClientNumber]);
this.SetText(ClientSocket[ClientNumber].RemoteEndPoint.ToString());

//this.StartReceiveMsgThread();

while (m == 1)
{
try
{
i = ClientSocket[ClientNumber].Receive(msgbuffer);
//ClientSocket[ClientNumber].BeginReceive(msgbuffer, 0, msgbuffer.Length, 0, new AsyncCallback(RecieveCallBack), ClientSocket[ClientNumber]);
}
catch (Exception)
{

MessageBox.Show("有一客户端断开", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
//return;
break;
}
msg = Encoding.Unicode.GetString(msgbuffer, 0, msgbuffer.Length);
this.SetText(msg);

System.Array.Clear(msgbuffer, 0, msgbuffer.Length);

if (msg.Trim() == "stop")
{
m = 0;
}

}
//this.SetText(msgbuffer.ToString());
ClientNumber++;

}

}

...全文
515 16 打赏 收藏 转发到动态 举报
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
focolo 2010-05-27
  • 打赏
  • 举报
回复
多线程不好玩,再加个UDP...
jiezi316 2010-05-27
  • 打赏
  • 举报
回复
。。。
你前面已经BEGINReceive了,那么ENDReceive的逻辑就应该在BEGINRECEIVE的异步回调函数里写啊。
而你后面又跟了个RECEIVE这个是阻塞的啊。没有数据来,就一直阻塞到的。你后面的连接怎么进得来呢?
allen3010 2010-05-27
  • 打赏
  • 举报
回复
怎么样把一个对象传给线程?
allen3010 2010-05-27
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 frank_lhj 的回复:]
从下面的代码开始到最后,放到一个单独的线程处理,,
ClientSocket[ClientNumber].BeginReceive(msgbuffer, 0, msgbuffer.Length, 0, new
AsyncCallback(RecieveCallBack), ClientSocket[ClientNumber]);


接收连接请求用一个独立的线程处理,针对每一个连接请求……
[/Quote]

怎么样把Socket传给线程啊?



allen3010 2010-05-27
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 frank_lhj 的回复:]
从下面的代码开始到最后,放到一个单独的线程处理,,
ClientSocket[ClientNumber].BeginReceive(msgbuffer, 0, msgbuffer.Length, 0, new
AsyncCallback(RecieveCallBack), ClientSocket[ClientNumber]);


接收连接请求用一个独立的线程处理,针对每一个连接请求……
[/Quote]

这位兄弟,“//这里同时将套接字以参数方式传递给工作线程
”这个怎么做,请给出代码提示,谢谢!你的方法有有前面有试过,但不知道怎么传参数,所以失败!谢谢!
yanzelin 2010-05-27
  • 打赏
  • 举报
回复
学习!学习!再学习~!
allen3010 2010-05-27
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 hhc123 的回复:]
引用 5 楼 hhc123 的回复:
要开一个Listen线程。
一个Receive线程。
你少了一个Listen线程。

不好意思啊,上面主要是说同步的。
你的例子,同步也有,异步也有,乱七八糟的。
[/Quote]

你好,这位兄弟可以说的明白点吗?
ksy 2010-05-26
  • 打赏
  • 举报
回复
看看msdn上socket的经典例子,同步异步都有:
http://msdn.microsoft.com/zh-cn/library/w89fhyex.aspx
hljlpz 2010-05-26
  • 打赏
  • 举报
回复
整个程序都崩溃了,每次收到新数据都会调用回调开启一个新线程处理,而你在回调中竟然用了一个死循环

frank_lhj 2010-05-26
  • 打赏
  • 举报
回复
从下面的代码开始到最后,放到一个单独的线程处理,,
ClientSocket[ClientNumber].BeginReceive(msgbuffer, 0, msgbuffer.Length, 0, new
AsyncCallback(RecieveCallBack), ClientSocket[ClientNumber]);


接收连接请求用一个独立的线程处理,针对每一个连接请求创建新工作线程,
监听请求如下面的模式:

private void RecieveAccept()
{
while(true)
{
//ClientNumber++;

ServerSocket.Listen(10);//开始监听,并且挂起数为10

ClientSocket[ClientNumber] = ServerSocket.Accept();

this.StartThread();//这里同时将套接字以参数方式传递给工作线程
......
}
hhc123 2010-05-26
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 hhc123 的回复:]
要开一个Listen线程。
一个Receive线程。
你少了一个Listen线程。
[/Quote]
不好意思啊,上面主要是说同步的。
你的例子,同步也有,异步也有,乱七八糟的。
hhc123 2010-05-26
  • 打赏
  • 举报
回复
要开一个Listen线程。
一个Receive线程。
你少了一个Listen线程。
捷哥1999 2010-05-26
  • 打赏
  • 举报
回复
看看这个例子,封装地比较好:
源代码和实现说明:
http://www.codeproject.com/KB/IP/AsyncSocketServerandClien.aspx

效果图:

anbin0814 2010-05-26
  • 打赏
  • 举报
回复
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.IO;

namespace AsyncTcpServer
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
setComboBoxCallback = new SetComboBoxCallback(SetComboBox);
setListBoxCallback = new SetListBoxCallback(SetListBox);
setRichTextBoxCallback = new SetRichTextBoxCallback(setRichText);
removeComboBoxItemsCallback = new RemoveComboBoxItemsCallback(RemoveComboBoxItems);
}
private bool isExit = false;
System.Collections.ArrayList clientList = new System.Collections.ArrayList();//保存连接所有的客服端
TcpListener listener;//监听客服端连接
private delegate void SetListBoxCallback(string str);
private SetListBoxCallback setListBoxCallback;
private delegate void SetRichTextBoxCallback(string str);
private SetRichTextBoxCallback setRichTextBoxCallback;
private delegate void SetComboBoxCallback(string str);
private SetComboBoxCallback setComboBoxCallback;
private delegate void RemoveComboBoxItemsCallback(ReadWriteObject readWriteObject);
private RemoveComboBoxItemsCallback removeComboBoxItemsCallback;

private EventWaitHandle allDone = new EventWaitHandle(false, EventResetMode.ManualReset);//用于线程同步,初始为非终止状态,使用手动设置方式

private void RemoveComboBoxItems(ReadWriteObject readWriteObject)
{
int index = clientList.IndexOf(readWriteObject);
comboBox1.Items.RemoveAt(index);
}

private void SetListBox(string str)
{
listBox1.Items.Add(str);
listBox1.SelectedIndex = listBox1.Items.Count - 1;
listBox1.ClearSelected();
}

private void setRichText(string str)
{
receive_text.AppendText(str);
}

private void SetComboBox(object obj)
{
comboBox1.Items.Add(obj);
}

private void AcceptConnect()
{
IPAddress[] ip = Dns.GetHostAddresses(Dns.GetHostName());//获取本机IP地址
listener = new TcpListener(ip[0], 51888);//创建监听
listener.Start();//启动监听
while(isExit==false)//循环监听客服端发过来的请求
{
try
{
allDone.Reset();//将事件设置为非终止状态,不让操作系统发出信号
AsyncCallback callback = new AsyncCallback(AcceptTcpClient);//引用在异步操作完成时调用的方法
listBox1.Invoke(setListBoxCallback, "开始等待客户连接");
listener.BeginAcceptTcpClient(callback, listener);//开始一个异步操作接收传来的连接尝试
allDone.WaitOne();//阻塞当前线程,直到收到客服端的连接信号
}
catch (Exception ex)
{
listBox1.Invoke(setListBoxCallback, ex.Message);
break;
}
}
}

private void AcceptTcpClient(IAsyncResult ar)//ar 异步操作状态
{ //是由 listener.BeginAcceptTcpClient(callback, listener)传递过来的
try
{
allDone.Set();//将事件状态设置为终止,让等待的一个或者多个线程继续
TcpListener myListener = (TcpListener)ar.AsyncState;
TcpClient client = myListener.EndAcceptTcpClient(ar);//异步接收传入的连接,并创建新的Tcplient对象处理远程主机通信
listBox1.Invoke(setListBoxCallback, "已接受客服连接:" + client.Client.RemoteEndPoint);
comboBox1.Invoke(setComboBoxCallback, client.Client.RemoteEndPoint.ToString());
ReadWriteObject readWriteObject = new ReadWriteObject(client);
clientList.Add(readWriteObject);
SendString(readWriteObject, "服务器已经接受连接,请通话!");
//开始异步读取
readWriteObject.netStream.BeginRead(readWriteObject.readBytes, 0, readWriteObject.readBytes.Length, ReadCallback, readWriteObject);
}
catch(Exception ex)
{
listBox1.Invoke(setListBoxCallback, ex.Message);
return;
}
}

private void ReadCallback(IAsyncResult ar)
{
try
{
ReadWriteObject readWriteObject = (ReadWriteObject)ar.AsyncState;
int count = readWriteObject.netStream.EndRead(ar);
receive_text.Invoke(setRichTextBoxCallback, string.Format("[来自{0}]{1}", readWriteObject.client.Client.RemoteEndPoint, System.Text.Encoding.UTF8.GetString(readWriteObject.readBytes, 0, count)));
if(isExit==false)
{
readWriteObject.InitReadArray();
readWriteObject.netStream.BeginRead(readWriteObject.readBytes, 0, readWriteObject.readBytes.Length, ReadCallback, readWriteObject);
}
}
catch(Exception ex)
{
listBox1.Invoke(setListBoxCallback, ex.Message);
}
}
private void SendString(ReadWriteObject readWriteObject,string str)
{
try
{
readWriteObject.writeBytes = System.Text.Encoding.UTF8.GetBytes(str + "\r\n");
//开始向流异步写入数据
readWriteObject.netStream.BeginWrite(readWriteObject.writeBytes, 0, readWriteObject.writeBytes.Length, new AsyncCallback(SendCallback), readWriteObject);
readWriteObject.netStream.Flush();//刷新流中的数据
listBox1.Invoke(setListBoxCallback, string.Format("向{0}发送:{1}", readWriteObject.client.Client.RemoteEndPoint, str));
}
catch(Exception ex)
{
listBox1.Invoke(setListBoxCallback, ex.Message);
}
}

private void SendCallback(IAsyncResult ar)
{
ReadWriteObject readWriteObject = (ReadWriteObject)ar.AsyncState;
try
{
readWriteObject.netStream.EndWrite(ar);//结束异步流的写入
}
catch(Exception ex)
{
listBox1.Invoke(setListBoxCallback, ex.Message);
comboBox1.Invoke(removeComboBoxItemsCallback, readWriteObject);
}
}
private void start_btn_Click(object sender, EventArgs e)
{
ThreadStart ts = new ThreadStart(AcceptConnect);//监听客服端的请求
Thread myThread = new Thread(ts);
myThread.Start();
start_btn.Enabled = false;
stop_btn.Enabled = true;
}

private void stop_btn_Click(object sender, EventArgs e)
{
isExit = true;
allDone.Set();
start_btn.Enabled = true;
stop_btn.Enabled = false;
}

private void send_btn_Click(object sender, EventArgs e)
{
int index = comboBox1.SelectedIndex;
if(index==-1)
{
MessageBox.Show("请先选择接受方,然后在发送");
}
else
{
ReadWriteObject obj = (ReadWriteObject)clientList[index];
SendString(obj, send_text.Text);
send_text.Clear();
}
}

private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
stop_btn_Click(null, null);
}





}
}
allen3010 2010-05-26
  • 打赏
  • 举报
回复
发送数据到指定的IP指定的端口没问题,但我其中一个Client端断开后Server 端就接受不到了其他Client端的数据了,郁闷中,还有Server怎么向指定的Client发送消息?请各位高手指教
缭绕飘渺 2010-05-26
  • 打赏
  • 举报
回复
没看出问题
发送数据到指定ip的指定端口不行吗

110,565

社区成员

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

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

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