.net 数据是否可以通过已调用BeginReceive但尚未调用EndReceive的套接字发送?(包括文件隧道的完整代码:)
我打开了两台机器之间的插座。在两端,它们调用BeginReceive并等待对方发送数据。任何一个都可以先发送数据,这取决于用户 我发现我不能双向发送数据,只有启动连接的应用程序才能发送数据 编辑:为文件隧道程序添加代码;添加的评论显示了我在哪里搞砸了.net 数据是否可以通过已调用BeginReceive但尚未调用EndReceive的套接字发送?(包括文件隧道的完整代码:),.net,sockets,asynchronous,.net,Sockets,Asynchronous,我打开了两台机器之间的插座。在两端,它们调用BeginReceive并等待对方发送数据。任何一个都可以先发送数据,这取决于用户 我发现我不能双向发送数据,只有启动连接的应用程序才能发送数据 编辑:为文件隧道程序添加代码;添加的评论显示了我在哪里搞砸了 //-----------Main.cs file------------ using System; using System.Collections.Generic; using System.ComponentModel; using Sys
//-----------Main.cs file------------
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net.Sockets;
using System.Threading;
using System.Net;
using System.IO;
public Socket listen_socket = null; //Listening socket (activated by clicking a button)
public List<Socket> connections = new List<Socket>(); //Stores all active connections to other server/client hybrids
public List<FileReceiver> receivers = new List<FileReceiver>(); //One FileReceiver for each active connection, handles receiving files on the connection
public List<FileSender> senders = new List<FileSender>(); //One FileSender per connection when a file is dropped in the interface, handles sending the file to each connected instance
public Queue<string> files_to_send = new Queue<string>(); //Queues files to send, if multiple files are dropped in the interface at once
public Main()
{
InitializeComponent();
Application.ApplicationExit += new EventHandler(Application_ApplicationExit);
lstFiles.DragEnter += new DragEventHandler(lstFiles_DragEnter);
lstFiles.DragDrop += new DragEventHandler(lstFiles_DragDrop);
}
private void lstFiles_DragEnter(object sender, DragEventArgs e)
{
e.Effect = DragDropEffects.All;
}
void lstFiles_DragDrop(object sender, DragEventArgs e)
{
string[] filepaths = e.Data.GetData( DataFormats.FileDrop ) as string[];
if (filepaths != null)
{
lock (files_to_send)
{
foreach (string filepath in filepaths)
files_to_send.Enqueue( filepath );
SendNextFile();
}
}
}
void SendNextFile()
{
lock (files_to_send)
{
if (senders.Count == 0 && files_to_send.Count > 0)
{
string filepath = files_to_send.Dequeue();
FileInfo fi = new FileInfo( filepath );
string filename = fi.Name;
MemoryStream ms = new MemoryStream();
BinaryWriter writer = new BinaryWriter( ms, Encoding.Unicode );
writer.Write( (int)filename.Length ); //known-length (4 bytes); serves as hint to protocol so it doesn't try to read string until it knows enough data has been received
writer.Write( filename ); //known length once previous int has been read
writer.Write( fi.CreationTimeUtc.ToBinary() ); //known-length (8 bytes)
writer.Write( fi.LastWriteTimeUtc.ToBinary() ); //known-length (8 bytes)
writer.Write( fi.LastAccessTimeUtc.ToBinary() ); //known-length (8 bytes)
writer.Write( (long)fi.Length ); //known-length (8 bytes)
byte[] header = ms.ToArray();
foreach (Socket socket in connections)
{
FileSender filesender = new FileSender( fi, header, socket );
filesender.SendComplete += new FileSenderCompletedEventHandler(filesender_SendComplete);
senders.Add( filesender );
}
}
}
}
void filesender_SendComplete(FileSender sender)
{
lock (files_to_send)
{
senders.Remove( sender );
if (senders.Count == 0)
SendNextFile();
}
if (!sender.CompletedSuccessfully)
MessageBox.Show( "Failed to send " + sender.fi.FullName + " to " + sender.socket.RemoteEndPoint.ToString() );
}
void Application_ApplicationExit(object sender, EventArgs e)
{
lock (connections)
{
foreach (Socket socket in connections)
{
try
{
socket.Shutdown( SocketShutdown.Both );
socket.Close();
}
catch (Exception err)
{
}
}
connections.Clear();
}
}
private void btnListen_Click(object sender, EventArgs e)
{
try
{
btnListen.Enabled = false;
if (listen_socket != null)
listen_socket.Close();
listen_socket = new Socket( AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp );
listen_socket.Bind( new IPEndPoint( IPAddress.Any, int.Parse( txtListenPort.Text.Trim() ) ) );
listen_socket.Listen( 1 );
listen_socket.BeginAccept( new AsyncCallback( handleAccept ), listen_socket );
}
catch (Exception err)
{
MessageBox.Show( err.Message + "\r\n" + err.StackTrace );
btnListen.Enabled = true;
if (listen_socket != null)
listen_socket.Close();
}
}
//INITIALIZES CONNECTION ON LISTENING END
private void BeginAccept_Callback( IAsyncResult result )
{
Socket listen_socket = result.AsyncState as Socket;
try
{
Socket connection = listen_socket.EndAccept( result );
lock (connections)
{
ConfigureSocket( connection );
FileReceiver receiver = AddSocketConnection( connection );
receiver.receiveData(); //<--WAS MISSING THIS!!! Initiates asynchronous BeginReceive call; FileReceiver handles processing the incoming stream as it arrives.
}
}
catch (Exception err)
{
MessageBox.Show( err.Message );
}
listen_socket.Close();
}
private void btnConnect_Click(object sender, EventArgs e)
{
string[] a = txtConnectIP.Text.Split( '.' );
IPAddress address = new IPAddress( new byte[] {byte.Parse( a[0] ), byte.Parse( a[1] ), byte.Parse( a[2] ), byte.Parse( a[3] ) } );
int port = int.Parse( txtConnectPort.Text );
Connect( address, port );
}
//INITIALIZES CONNECTION ON CONNECTING END
private void Connect( IPAddress address, int port )
{
Socket connection = new Socket( AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp );
lock (connections)
{
try
{
ConfigureSocket( connection );
connection.Connect( address, port );
FileReceiver receiver = AddSocketConnection( connection );
receiver.receiveData(); //<--REMEMBERED IT HERE!!! So I could receive files on the connecting end.
}
catch (Exception err)
{
MessageBox.Show( err.Message );
}
}
}
private void DisplayConnectionsCount( int count )
{
txtConnections.Text = count.ToString();
}
private void ConfigureSocket( Socket connection )
{
connection.SetSocketOption( SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true );
connection.UseOnlyOverlappedIO = true;
connection.LingerState = new LingerOption( false, 0 );
}
private FileReceiver AddSocketConnection( Socket connection )
{
lock (connections)
{
connections.Add( connection );
Invoke( new Action<string>( DisplayConnectionCount ), connections.Count );
FileReceiver receiver = new FileReceiver( connection );
receivers.Add( receiver );
receiver.ReceiverShutdown += new FileReceiverShutdownEventHandler( receiver_Shutdown );
receiver.FileReceived += new FileReceiverReceiveEventHandler(receiver_FileReceived);
receiver.ReceiverDownloading += new FileReceiverDownloadingEventHandler(receiver_ReceiverDownloading);
return receiver;
}
}
private void RemoveSocketConnection( FileReceiver receiver )
{
lock (connections)
{
try
{
receiver.ReceiverShutdown -= new FileReceiverShutdownEventHandler( receiver_Shutdown );
receiver.FileReceived -= new FileReceiverReceiveEventHandler(receiver_FileReceived);
receiver.ReceiverDownloading -= new FileReceiverDownloadingEventHandler(receiver_ReceiverDownloading);
receivers.Remove( receiver );
connections.Remove( receiver.connection );
Invoke( new Action<int>( DisplayConnectionsCount ), connections.Count );
}
catch (Exception err)
{
MessageBox.Show( err.Message + "\r\n" + err.StackTrace );
}
}
}
void receiver_ReceiverDownloading(FileReceiver receiver)
{
if (InvokeRequired)
Invoke( new FileReceiverDownloadingEventHandler( receiver_ReceiverDownloading ), receiver );
else
Text = "File Tunnel - Received " + receiver.BytesReceived + " bytes...";
}
void receiver_FileReceived(FileInfo fi)
{
if (lstFiles.InvokeRequired)
lstFiles.BeginInvoke( new FileReceiverReceiveEventHandler( receiver_FileReceived ), fi );
else
{
lstFiles.Items.Add( fi );
Text = "File Tunnel";
}
}
public void receiver_Shutdown( FileReceiver receiver )
{
RemoveSocketConnection( receiver );
}
//----FileSender.cs file------
public delegate void FileSenderCompletedEventHandler( FileSender sender );
public class FileSender
{
public Socket socket;
public FileInfo fi;
public FileStream fs;
public event FileSenderCompletedEventHandler SendComplete;
private byte[] header;
public bool CompletedSuccessfully = false;
public FileSender( FileInfo fi, byte[] header, Socket socket )
{
this.fi = fi;
this.socket = socket;
this.header = header;
try
{
socket.BeginSendFile( fi.FullName, header, null, TransmitFileOptions.UseSystemThread, new AsyncCallback( send_File ), this );
}
catch (Exception err)
{
MessageBox.Show( err.Message + "\r\n" + err.StackTrace );
CompleteCallback();
}
}
private void send_File( IAsyncResult result )
{
try
{
socket.EndSendFile( result );
CompletedSuccessfully = true;
}
catch (Exception err)
{
MessageBox.Show( err.Message + "\r\n" + err.StackTrace );
}
finally
{
CompleteCallback();
}
}
private void CompleteCallback()
{
try
{
if (SendComplete != null)
SendComplete( this );
}
catch (Exception err)
{
MessageBox.Show( err.Message + "\r\n" + err.StackTrace );
}
}
}
//----FileReceiver.cs file------
public delegate void FileReceiverReceiveEventHandler( FileInfo fi );
public delegate void FileReceiverShutdownEventHandler( FileReceiver receiver );
public delegate void FileReceiverDownloadingEventHandler( FileReceiver receiver );
public enum FileReceiverProtocolStep
{
ReadFilenameLength,
ReadFilename,
ReadTimestamps,
ReadFileLength,
ReadFile
}
public class FileReceiver
{
public const int BUFFER_SIZE = 1024 * 1024;
public Socket connection;
private byte[] buffer = new byte[BUFFER_SIZE];
private long last_read_position = 0;
private FileReceiverProtocolStep protocol_step = FileReceiverProtocolStep.ReadFilenameLength;
private MemoryStream received_data = new MemoryStream();
public event FileReceiverReceiveEventHandler FileReceived;
public event FileReceiverShutdownEventHandler ReceiverShutdown;
public event FileReceiverDownloadingEventHandler ReceiverDownloading;
public FileReceiver( Socket connection )
{
this.connection = connection;
}
public long BytesReceived
{
get {return received_data.Length;}
}
public void receiveData()
{
connection.BeginReceive( buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback( receiveDataCallback ), connection );
}
private void receiveDataCallback( IAsyncResult result )
{
Socket connection = result.AsyncState as Socket;
int bytes_read;
try
{
bytes_read = connection.EndReceive( result );
if (bytes_read == 0)
{
if (received_data.Length > 0)
ProcessMemoryStream();
else
{
ShutDown(); //Nothing recieved... socket probably closed
return;
}
}
else
{
lock (received_data)
received_data.Write( buffer, 0, bytes_read );
ProcessMemoryStream(); //Process as much of the memory stream as possible
if (ReceiverDownloading != null)
ReceiverDownloading( this );
}
}
catch (Exception err)
{
MessageBox.Show( err.Message + "\r\n" + err.StackTrace );
ShutDown();
return;
}
receiveData();
}
private void ShutDown()
{
try
{
connection.Shutdown( SocketShutdown.Both );
connection.Close();
}
catch (Exception err)
{
MessageBox.Show( err.Message + "\r\n" + err.StackTrace );
}
if (ReceiverShutdown != null)
ReceiverShutdown( this );
}
private int filename_length;
private string filename;
private DateTime timestamp_creation;
private DateTime timestamp_modified;
private DateTime timestamp_lastaccess;
long file_length;
private void ProcessMemoryStream()
{
//Prepare binary reader
lock (received_data)
{
BinaryReader reader = new BinaryReader( received_data, Encoding.Unicode );
received_data.Position = last_read_position;
next_step:
long bytes_available = received_data.Length - received_data.Position;
switch (protocol_step)
{
case FileReceiverProtocolStep.ReadFilenameLength:
//Read filename
if (bytes_available >= 4)
{
filename_length = reader.ReadInt32();
protocol_step = FileReceiverProtocolStep.ReadFilename;
goto next_step;
}
break;
case FileReceiverProtocolStep.ReadFilename:
if (bytes_available >= filename_length)
{
filename = reader.ReadString();
protocol_step = FileReceiverProtocolStep.ReadTimestamps;
goto next_step;
}
break;
case FileReceiverProtocolStep.ReadTimestamps:
if (bytes_available >= 24)
{
//Read timestamps
timestamp_creation = DateTime.FromBinary( reader.ReadInt64() );
timestamp_modified = DateTime.FromBinary( reader.ReadInt64() );
timestamp_lastaccess = DateTime.FromBinary( reader.ReadInt64() );
protocol_step = FileReceiverProtocolStep.ReadFileLength;
goto next_step;
}
break;
case FileReceiverProtocolStep.ReadFileLength:
if (bytes_available >= 8)
{
file_length = reader.ReadInt64();
protocol_step = FileReceiverProtocolStep.ReadFile;
goto next_step;
}
break;
case FileReceiverProtocolStep.ReadFile:
if (bytes_available >= file_length)
{
FileInfo fi = new FileInfo( filename.Replace( '\\', '_' ).Replace( '/', '_' ) ); //Disable relative path specification
FileStream fs = fi.Open( FileMode.Create, FileAccess.Write, FileShare.Read );
long bytes_to_save = file_length;
while (bytes_to_save > 0)
{
int bytes_to_read = (int)Math.Min( (long)BUFFER_SIZE, bytes_to_save );
bytes_to_save -= bytes_to_read;
fs.Write( reader.ReadBytes( bytes_to_read ), 0, bytes_to_read );
}
fs.Close();
fi.CreationTimeUtc = timestamp_creation;
fi.LastWriteTimeUtc = timestamp_modified;
fi.LastAccessTimeUtc = timestamp_lastaccess;
received_data.Position = 0;
received_data.SetLength( 0 );
//Reset protocol for next file
protocol_step = FileReceiverProtocolStep.ReadFilenameLength; //Ready for next file
filename_length = 0;
filename = String.Empty;
timestamp_creation = DateTime.MinValue;
timestamp_modified = DateTime.MinValue;
timestamp_lastaccess = DateTime.MinValue;
file_length = 0;
if (FileReceived != null)
FileReceived( fi );
}
break;
}
//Backup the last read position, and set the position to the end of the stream for subsquent write operations
last_read_position = received_data.Position;
received_data.Seek( 0, SeekOrigin.End );
}
}
}
/------------Main.cs文件------------
使用制度;
使用System.Collections.Generic;
使用系统组件模型;
使用系统数据;
使用系统图;
使用System.Linq;
使用系统文本;
使用System.Windows.Forms;
使用System.Net.Sockets;
使用系统线程;
Net系统;
使用System.IO;
公共套接字侦听_Socket=null//侦听套接字(通过单击按钮激活)
公共列表连接=新列表()//存储到其他服务器/客户机的所有活动连接
公共列表接收者=新列表()//每个活动连接有一个FileReceiver,用于处理连接上的文件接收
公共列表发送者=新列表()//每个连接一个FileSender在接口中删除文件时,处理将文件发送到每个连接的实例
公共队列文件_to_send=新队列()//如果同时在接口中删除多个文件,则对要发送的文件进行排队
公用干管()
{
初始化组件();
Application.ApplicationExit+=新的事件处理程序(Application\u ApplicationExit);
lstFiles.DragEnter+=新的DragEventHandler(lstFiles\u DragEnter);
lstFiles.DragDrop+=新的DragEventHandler(lstFiles\u DragDrop);
}
私有void lstu DragEnter(对象发送方,DragEventArgs e)
{
e、 效果=DragDropEffects.All;
}
void lstFiles_DragDrop(对象发送方,DragEventArgs e)
{
string[]filepath=e.Data.GetData(DataFormats.FileDrop)作为字符串[];
if(文件路径!=null)
{
锁定(要发送的文件)
{
foreach(文件路径中的字符串文件路径)
文件到发送队列(文件路径);
SendNextFile();
}
}
}
void SendNextFile()
{
锁定(要发送的文件)
{
if(senders.Count==0&&files\u to\u send.Count>0)
{
字符串filepath=files_to_send.Dequeue();
FileInfo fi=新的FileInfo(filepath);
字符串filename=fi.Name;
MemoryStream ms=新的MemoryStream();
BinaryWriter=新的BinaryWriter(ms,Encoding.Unicode);
writer.Write((int)filename.Length);//已知长度(4字节);用作协议的提示,所以在它知道已收到足够的数据之前,它不会尝试读取字符串
writer.Write(filename);//读取上一个int后的已知长度
writer.Write(fi.CreationTimeUtc.ToBinary());//已知长度(8字节)
writer.Write(fi.LastWriteTimeUtc.ToBinary());//已知长度(8字节)
writer.Write(fi.LastAccessTimeUtc.ToBinary());//已知长度(8字节)
writer.Write((long)fi.Length);//已知长度(8字节)
字节[]头=ms.ToArray();
foreach(插座连接)
{
FileSender FileSender=新的FileSender(fi、头、套接字);
filesender.sendplete+=新的filesendercompletedventhandler(filesender\u sendplete);
添加(filesender);
}
}
}
}
无效filesender\u SendComplete(filesender发件人)
{
锁定(要发送的文件)
{
发件人。删除(发件人);
如果(senders.Count==0)
SendNextFile();
}
如果(!sender.CompletedSuccessfully)
MessageBox.Show(“未能将”+sender.fi.FullName+“发送到”+sender.socket.RemoteEndPoint.ToString());
}
无效应用程序\应用程序退出(对象发送方、事件参数)
{
锁(连接)
{
foreach(插座连接)
{
尝试
{
socket.Shutdown(SocketShutdown.Both);
socket.Close();
}
捕获(异常错误)
{
}
}
连接。清除();
}
}
私有void btnListen\u单击(对象发送方,事件参数e)
{
尝试
{
btnListen.Enabled=false;
if(侦听套接字!=null)
监听插座。关闭();
listen_socket=新套接字(AddressFamily.InterNetwork、SocketType.Stream、ProtocolType.Tcp);
listen_socket.Bind(新的IPEndPoint(IPAddress.Any,int.Parse(txtListenPort.Text.Trim()));
监听插座。监听(1);
listen\u socket.beginacept(新的异步回调(handleacept),listen\u socket);
}
捕获(异常错误)
{
MessageBox.Show(err.Message+“\r\n”+err.StackTrace);
btnListen.Enabled=true;
if(侦听套接字!=null)
监听插座。关闭();
}
}
//初始化侦听端的连接
私有void BeginAccept_回调(IAsyncResult结果)
{
Socket listen\u Socket=result.AsyncState作为套接字;
尝试
{
套接字连接=侦听\u Socket.EndAccept(结果);
锁(连接)
{
配置套接字(连接);
FileReceiver接收器=AddSocketConnection(连接);
receiver.receiveData();/=4)
{
filename_length=reader.ReadInt32();
协议步骤=FileReceiveProtocolStep.ReadFilename;
转到下一步;
}
打破
案例文件ReceiverProtocolStep.ReadFilename:
如果(字节数可用>=文件名长度)
{
filename=reader.ReadString();
协议步骤=FileReceiveProtocolStep.ReadTimestaps;
转到下一步;
}
打破