异步socket时send数据包后EndReceive

dasihg 2010-02-25 10:13:07
private void SendCallback(IAsyncResult ar)
{ // 从state对象中获取socket
Socket client = (Socket)ar.AsyncState; // 完成数据发送.
int bytesSent = client.EndSend(ar);
}

private static void ReceiveCallback(IAsyncResult ar)
{ // 从输入参数异步state对象中获取state和socket对象

StateObject state = (StateObject)ar.AsyncState;
Socket client = state.workSocket; //从远程设备读取消息头
int bytesRead = client.EndReceive(ar);

if (bytesRead > 0)
{ // 有数据,存储.

string headstr = Encoding.Default.GetString(state.buffer, 0, bytesRead);

state.sb.Append(headstr); // 继续读取.

client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state);
}
else
{ // 所有数据读取完毕.
if (state.sb.Length > 1) { response = state.sb.ToString(); } // 所有数据读取完毕的指示信号.
receiveDone.Set();
}

}
...全文
791 22 打赏 收藏 转发到动态 举报
写回复
用AI写文章
22 条回复
切换为时间正序
请发表友善的回复…
发表回复
q136170746 2011-10-04
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 sp1234 的回复:]

实际上,也不知道怎么回事,msdn中的异步通讯代码是我在msdn上见过最烂的代码。msdn中的代码使用了一个同步信号量,既用异步代码来模拟同步控制流程。你可以看到msdn的所谓异步编程范例程序的主线程上是使用一个循环来控制的,这样做,你的程序没有真正用到异步编程的好处。

实际上在异步编程代码中,主线程也根本不需要任何循环语句,而处理接收信息的代码最后也根本不需要 receiveDone.S……
[/Quote]
那这里不用循环,该怎么写,求指教啊。。。
dasihg 2010-02-27
  • 打赏
  • 举报
回复
引用 17 楼 wodegege10 的回复:
if (bytesRead > 0)
这个不是数据接收完的判断

是该 连接是否断开的判断


设了断点,ReceiveCallback都没进去
dasihg 2010-02-27
  • 打赏
  • 举报
回复

private static void ReceiveCallback2(IAsyncResult ar)
{
//检索异步结构对象并且处理从异步结构对象过来的套接字
StateObject state = (StateObject)ar.AsyncState;
Socket handler = state.workSocket;

//Socket handler = state.workSocket;
//EndReceive 方法完成在 BeginReceive 方法中启动的异步读取操作。返回值接收到的字节数。
int bytesRead = 0;
try
{
if (handler != null && handler.Connected)
{
bytesRead = handler.EndReceive(ar);//从客户端套接字读取数据
}
}
catch (Exception ex)
{
MessageBox.Show("读取错误:" + ex.Message.ToString());
}

if (bytesRead == 0)
{
receiveDone.Set();
}

if (bytesRead > 0)//可能会有更多的数据,因此存储迄今为止收到的数据。
{
state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, bytesRead));
//检查文件结束标志,如果不是结束,则继续读取更多的数据
response = state.sb.ToString();
if (response.IndexOf("EOF") > -1)
{//所有数据都已经读取完毕,则处理

receiveDone.Set();
}
else
{//还有数据需要读取,继续读数据
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback2), state);
}
}

}


private void Send(Socket client, String data)
{
// 格式转换.
data = data.Replace(" ", "");
int len = data.Length;
byte[] byteData = new byte[len / 2];
int j = 0;
for (int i = 0; i < len; i = i + 2)
{
byteData[j] = (byte)Convert.ToInt32(data.Substring(i, 2), 16);
j++;
}

// 开始发送数据到远程设备.
client.BeginSend(byteData, 0, byteData.Length, 0, new AsyncCallback(SendCallback), client);
}

private void SendCallback(IAsyncResult ar)
{ // 从state对象中获取socket
Socket client = (Socket)ar.AsyncState; // 完成数据发送.
int bytesSent = client.EndSend(ar);


// SetText("Sent " + bytesSent + " bytes to server." + "\r\n"); // 指示数据已经发送完成,主线程继续.
sendDone.Set();
}

void writetoX(byte[] bt)
{
string aa = "";

for (int i = 0; i < bt.Length; i++)
{
if (bt[i].ToString() == "0")
{
aa += " ";
continue;
}
if (bt[i].ToString("X").Length != 1)
{
aa += bt[i].ToString("X");
}
else
{
aa += "0" + bt[i].ToString("X");
}

}

StreamWriter sw = File.AppendText("c:\\test2.txt");
sw.WriteLine(DateTime.Now);
sw.WriteLine(aa);
sw.WriteLine(HexToStr(aa));
sw.Flush();
sw.Close();

}

}
}
dasihg 2010-02-27
  • 打赏
  • 举报
回复
引用 16 楼 xingyuebuyu 的回复:
贴完整代码吧,这样看不出问题


using System;
using System.Text;
using System.Windows.Forms;
using System.Net.Sockets;
using System.Net;
using System.Threading;
using System.Globalization;
using System.IO;

namespace test2
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

// ManualResetEvent instances signal completion.
private static ManualResetEvent connectDone;
private static ManualResetEvent sendDone;
private static ManualResetEvent receiveDone;
// The response from the remote device.
private static String response = String.Empty;

bool isESTA = false; Socket myclient;//是否保持连接

private void btnSend_Click(object sender, EventArgs e)
{
isESTA = checkBox1.Checked;//是否保持连接
connectDone = new ManualResetEvent(false);
sendDone = new ManualResetEvent(false);
receiveDone = new ManualResetEvent(false);

StartClient(txtSendContent.Text.Trim(), isESTA);

}

private void button1_Click(object sender, EventArgs e)
{ //清空返回数据
richTextBox1.Clear();
}


private void button2_Click(object sender, EventArgs e)
{ //断开连接
if (myclient != null)
{
myclient.Shutdown(SocketShutdown.Both);
myclient.Close();
myclient = null;
}
}


/// <summary>
/// 发送包头数据
/// </summary>
/// <param name="sendtxt">包头数据</param>
/// <param name="keepalive">是否保持连接</param>
private void StartClient(string sendtxt, bool keepalive)
{
try
{
Socket client = myclient;

IPAddress ipAddress = IPAddress.Parse(txtHostIP.Text.Trim());
IPEndPoint remoteEP = new IPEndPoint(ipAddress, Convert.ToInt32(txtPort.Text.Trim()));

if (client == null)
{
client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
client.BeginConnect(remoteEP, new AsyncCallback(ConnectCallback), client);
connectDone.WaitOne();
}
//if (sendtxt != "")
//{
Send(client, sendtxt);
sendDone.WaitOne();
if (checkBox2.Checked)
{
Receive(client, comboBox1.Text, txtEnCode.Text.Trim());
receiveDone.WaitOne();
}
// }
SetText("Response received :\r\n" + response + "\r\n");
if (!keepalive)
{
client.Shutdown(SocketShutdown.Both);
client.Close();
myclient = null;
}
else
{
myclient = client;
}
}
catch (Exception e)
{
SetText(e.ToString() + "\r\n");
}

}



delegate void SetTextCallback(string text);
private void SetText(string text)
{
if (this.richTextBox1.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] { text });
}
else
{
richTextBox1.AppendText(text);
}
}

public string HexToStr(string mHex) // 返回十六进制代表的字符串
{
mHex = mHex.Replace(" ", "");
if (mHex.Length <= 0) return "";
byte[] vBytes = new byte[mHex.Length / 2];
for (int i = 0; i < mHex.Length; i += 2)
if (!byte.TryParse(mHex.Substring(i, 2), NumberStyles.HexNumber, null, out vBytes[i / 2]))
vBytes[i / 2] = 0;
return ASCIIEncoding.Default.GetString(vBytes);
}

public class StateObject
{
// Client socket.
public Socket workSocket = null;
// Size of receive buffer.
public const int BufferSize = 1024;
// Receive buffer.
public byte[] buffer = new byte[BufferSize];
// Received data string.
public StringBuilder sb = new StringBuilder();
}

private void ConnectCallback(IAsyncResult ar)
{ // 从state对象获取socket.
Socket client = (Socket)ar.AsyncState; // 完成连接.
client.EndConnect(ar);
// SetText("Socket connected to " + client.RemoteEndPoint.ToString() + "\r\n"); // 连接已完成,主线程继续.
connectDone.Set();
}

private static void Receive(Socket client, string xy, string bm)
{
if (xy == "HTTP")
{
response = httppro.ReceiveData(client, bm);

receiveDone.Set();
}
else
{
// 构造容器state.
StateObject state = new StateObject();
state.workSocket = client; // 从远程目标接收数据.

client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state);
}
}

private static void getreceiveData(Socket socket)
{
StringBuilder header = new StringBuilder();

while (true)
{
byte[] data = new byte[1];
//接收一个字节
int rece = socket.Receive(data, 1, SocketFlags.None);

//转换为char
char c = (char)data[0];

header.Append(c);

if (header.ToString().IndexOf("┅") > 0)
{
response = header.ToString();
break;
}
}
}

private static void ReceiveCallback(IAsyncResult ar)
{ // 从输入参数异步state对象中获取state和socket对象

StateObject state = (StateObject)ar.AsyncState;
Socket client = state.workSocket; //从远程设备读取消息头
int bytesRead = client.EndReceive(ar);

if (bytesRead > 0)
{ // 有数据,存储.

string headstr = Encoding.Default.GetString(state.buffer, 0, bytesRead);

state.sb.Append(headstr); // 继续读取.
if (headstr.IndexOf("b") > -1)//
{

receiveDone.Set();
return;
}
client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state);
}
else
{ // 所有数据读取完毕.
if (state.sb.Length > 1) { response = state.sb.ToString(); } // 所有数据读取完毕的指示信号.
receiveDone.Set();
}

}
xingyuebuyu 2010-02-27
  • 打赏
  • 举报
回复
Receive和ReceiveCallback方法之前的static 去掉
wenbin 2010-02-26
  • 打赏
  • 举报
回复
if (bytesRead > 0)
这个不是数据接收完的判断

是该 连接是否断开的判断

xingyuebuyu 2010-02-26
  • 打赏
  • 举报
回复
贴完整代码吧,这样看不出问题
  • 打赏
  • 举报
回复
sorry,“3.1 如果结束,关闭连接,返回累计接收到数据,退出。”这句话可能有点误导。

实际我是想写:3.1 如果结束,关闭连接,使用累计接收到数据通知给使用者(事件或者delegate),退出。

也就是说,并不是receiveDone.Set(),而是在线程中回调使用者,传递接收到的数据给调用者的回调程序来干一件事(例如在GUI上显示)。这是异步处理过程。而receiveDone.Set我从你的代码上猜测你是在一开始搞了同步信号量控制,这种用异步代码来模拟同步控制的做法我觉得要不得。
  • 打赏
  • 举报
回复
看不到你的第一个BeginReceive 写在那里,不知道接收过程是如何启动的。
  • 打赏
  • 举报
回复
短连接的客户端程序流程大致应这样:


主线程:

1. 开始异步connect,连接指定host、指定端口。


connect回调方法:
1. End异步Connect。
2. 开始异步Send,一次性发送完整的数据包。

Send回调方法:
1. End异步Send。
2. 开始异步Receive。

Receive回调方法:
1. End异步Receive。
2. 保存缓冲区中的数据。
3. 判断是否消息结束:
3.1 如果结束,关闭连接,返回累计接收到数据,退出。
3.2 如果没有结束,开始异步Receive。


服务端的程序,则顺序相反,它是异步Accept,然后异步Receive,(递归调用异步Receive直到接收结束)然后异步Send。
qldsrx 2010-02-25
  • 打赏
  • 举报
回复
你凭什么说EndReceive不执行,你有断点调试过吗?
只要进入ReceiveCallback回调函数,“int bytesRead = client.EndReceive(ar); ”这句肯定会被执行,除非未收到数据。
  • 打赏
  • 举报
回复
你的代码不全,看不出第一个调用 client.BeginReceive 的代码。你是想在Send之后Receive?那么在SendCallback最后一句调用 BeginReceive 啊!
guoyichao 2010-02-25
  • 打赏
  • 举报
回复
不要在异步回调处理的时候再启动异步接收,接收缓存有可能并发冲突。
  • 打赏
  • 举报
回复
实际上,也不知道怎么回事,msdn中的异步通讯代码是我在msdn上见过最烂的代码。msdn中的代码使用了一个同步信号量,既用异步代码来模拟同步控制流程。你可以看到msdn的所谓异步编程范例程序的主线程上是使用一个循环来控制的,这样做,你的程序没有真正用到异步编程的好处。

实际上在异步编程代码中,主线程也根本不需要任何循环语句,而处理接收信息的代码最后也根本不需要 receiveDone.Set() 这类。
dasihg 2010-02-25
  • 打赏
  • 举报
回复
异步socket时send数据包后EndReceive不执行,高手帮帮忙!

但用截包工具可以看到数据包已成功返回!
dasihg 2010-02-25
  • 打赏
  • 举报
回复
引用 12 楼 xingyuebuyu 的回复:
在SendCallback函数中没有的调用啊,你发送完了要设置sendDone, 不让程序会在sendDone.WaitOne(); 处等待sendDone.Set()的调用,你Receive(client)根本就不会执行,有怎么会执行 ReceiveCallback()啊。


有sendDone.Set()的,调试这个已经执行
dasihg 2010-02-25
  • 打赏
  • 举报
回复
引用 11 楼 dasihg 的回复:
SendCallback里面有sendDone.Set()

        private void SendCallback(IAsyncResult ar)
        {  // 从state对象中获取socket 
            Socket client = (Socket)ar.AsyncState;  // 完成数据发送. 
            int bytesSent = client.EndSend(ar);
           
     
            // SetText("Sent " + bytesSent + " bytes to server." + "\r\n");  // 指示数据已经发送完成,主线程继续. 
            sendDone.Set();
        }


有的,开始我打漏了
dasihg 2010-02-25
  • 打赏
  • 举报
回复
引用 8 楼 sp1234 的回复:
sorry,“3.1 如果结束,关闭连接,返回累计接收到数据,退出。”这句话可能有点误导。

实际我是想写:3.1 如果结束,关闭连接,使用累计接收到数据通知给使用者(事件或者delegate),退出。

也就是说,并不是receiveDone.Set(),而是在线程中回调使用者,传递接收到的数据给调用者的回调程序来干一件事(例如在GUI上显示)。这是异步处理过程。而receiveDone.Set我从你的代码上猜测你是在一开始搞了同步信号量控制,这种用异步代码来模拟同步控制的做法我觉得要不得。



http协议的可以接受,但TCP的好像根本不会接受,发送完数据就直接返回数据,好像是socket自己接收的,不用我另外再接受;就是建立连接一样,发送连接请求,返回连接成功数据,不用EndReceive;

有什么例子提供我参考下吗?谢谢!
xingyuebuyu 2010-02-25
  • 打赏
  • 举报
回复
在SendCallback函数中没有sendDone.Set()的调用啊,你发送完了要设置sendDone, 不让程序会在sendDone.WaitOne(); 处等待sendDone.Set()的调用,你Receive(client)根本就不会执行,有怎么会执行 ReceiveCallback()啊。
dasihg 2010-02-25
  • 打赏
  • 举报
回复
SendCallback里面有sendDone.Set()

private void SendCallback(IAsyncResult ar)
{ // 从state对象中获取socket
Socket client = (Socket)ar.AsyncState; // 完成数据发送.
int bytesSent = client.EndSend(ar);


// SetText("Sent " + bytesSent + " bytes to server." + "\r\n"); // 指示数据已经发送完成,主线程继续.
sendDone.Set();
}
加载更多回复(2)

110,534

社区成员

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

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

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