#c# #file #tcp #transfer
#c# #файл #tcp #передача
Вопрос:
У меня есть клиент-получатель и клиент-отправитель, которые в значительной степени передают файлы. Это то, что у меня пока есть на приемнике:
Thread t1;
int flag = 0;
string receivedPath;
public delegate void MyDelegate(string s);
int bytesRead = 0;
bool endReceive = false;
public Form1()
{
t1 = new Thread(new ThreadStart(StartListening));
t1.Start();
InitializeComponent();
}
public class StateObject
{
// Client socket.
public Socket workSocket = null;
public const int BufferSize = 1024*100;
// Receive buffer.
public byte[] buffer = new byte[BufferSize];
}
public static ManualResetEvent allDone = new ManualResetEvent(false);
public void StartListening()
{
byte[] bytes = new Byte[1024*1000];
IPEndPoint ipEnd = new IPEndPoint(IPAddress.Any, 9050);
Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
listener.Bind(ipEnd);
listener.Listen(100);
while (true)
{
allDone.Reset();
listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);
allDone.WaitOne();
if (endReceive)
{
listener.Disconnect(true);
}
}
}
catch (Exception ex)
{
}
}
public void AcceptCallback(IAsyncResult ar)
{
allDone.Set();
Socket listener = (Socket)ar.AsyncState;
Socket handler = listener.EndAccept(ar);
StateObject state = new StateObject();
state.workSocket = handler;
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), state);
flag = 0;
}
public void ReadCallback(IAsyncResult ar)
{
int fileNameLen = 1;
String content = String.Empty;
StateObject state = (StateObject)ar.AsyncState;
Socket handler = state.workSocket;
try
{
bytesRead= handler.EndReceive(ar);
}
catch (SocketException x)
{
MessageBox.Show("File Transfer was cancelled");
Invoke(new MyDelegate(LabelWriter), new object[] { "Waiting for connections" });
if (File.Exists(receivedPath))
{
File.Delete(receivedPath);
return;
}
}
if (endReceive)
{
handler.Disconnect(true);
if (File.Exists(receivedPath))
{
File.Delete(receivedPath);
}
return;
}
if (bytesRead > 0)
{
if (flag == 0)
{
fileNameLen = BitConverter.ToInt32(state.buffer, 0);
string fileName = Encoding.UTF8.GetString(state.buffer, 4, fileNameLen);
receivedPath = fileName;
Invoke(new MyDelegate(LabelWriter), new object[] { "Receiving File: " fileName });
flag ;
}
if (flag >= 1)
{
BinaryWriter writer = new BinaryWriter(File.Open(receivedPath, FileMode.Append));
if (flag == 1)
{
writer.Write(state.buffer, 4 fileNameLen, bytesRead - (4 fileNameLen));
flag ;
ReleaseMemory();
}
else
writer.Write(state.buffer, 0, bytesRead);
writer.Close();
try
{
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), state);
}
catch (SocketException exc)
{
MessageBox.Show("File Transfer was cancelled");
Invoke(new MyDelegate(LabelWriter), new object[] { "Waiting for connections" });
if (File.Exists(receivedPath))
{
File.Delete(receivedPath);
return;
}
}
}
}
else
Invoke(new MyDelegate(LabelWriter), new object[] {"Data Received"});
}
Чего я хочу добиться, так это возможности отменить передачу во время ее выполнения. Я имел в виду, что для логического значения «EndReceive» было установлено значение false, и каждый раз, когда вызывается метод ReadCallBack, проверяется значение EndReceive. Если значение равно false, я отключаю сокет. Это работает, останавливая получение файла, однако приложение-отправитель просто зависает. В основном, так я отправляю:
while (true)
{
int index = 0;
while (index < fs.Length)
{
int bytesRead = fs.Read(fileData, index, fileData.Length - index);
if (bytesRead == 0)
{
break;
}
index = bytesRead;
}
if (index != 0)
{
try
{
clientSock.Send(fileData, index, SocketFlags.None);
}
catch (Exception sexc)
{
MessageBox.Show("Transfer Cancelled");
return;
}
ReleaseMemory();
if ((progressBar1.Value (1024 * 1000)) > fs.Length)
{
progressBar1.Value = ((int)fs.Length - progressBar1.Value);
}
else
progressBar1.Value = (1024 * 1000);
lblSent.Text = index.ToString();
}
if (index != fileData.Length)
{
ReleaseMemory();
progressBar1.Value = 0;
clientSock.Close();
fs.Close();
break;
}
}
Есть мысли?
Комментарии:
1. Если я не ошибаюсь, если вы не выполнили надлежащее закрытие соединения, вы увидите, что вы продолжаете получать, но всего 0 байт. Ранее я создавал приложение таким образом, чтобы клиент автоматически переподключался, если соединение потеряно. Итак, когда соединение потеряно, я получу 0 байт, поэтому в этот момент я просто закрываю клиент и восстанавливаю соединение обратно.
Ответ №1:
Я думаю, что сложно принудительно прервать массовую передачу, которую вы выполняете, и закрыть ее чисто, просто используя TCP. Что, если вы возьмете размер вашего блока 1024 и после каждой передачи кБ будете отправлять быстрый байт подтверждения или nack от получателя отправителю? Nack, указывающий, что передача должна быть прервана, ack, указывающий на продолжение.
К сожалению, для этого требуется полное дублирование для получателя / отправителя, и будьте осторожны! Несмотря на то, что это асинхронный ввод-вывод, вам нужно вызывать BeginReceive и BeginSend в отдельных потоках, если вы планируете чтение и запись из одного сокета.