2009-08-09 4 views
6

Как приложение C# может легко связываться с экземпляром, присутствующим на другом компьютере, который находится в одной сети, и передает файлы и данные?Как приложение C# может легко общаться и передавать файлы в сети?

Предполагая, что компьютеры в сети имеют фиксированные локальные IP-адреса, и каждый из них знает IP-адреса других. Был бы также способ общения, если IP-адреса неизвестны? основанный на каком-то протоколе обнаружения?

Я слышал, что услуга «Bonjour» от Apple была хорошим протоколом. Можем ли мы общаться через него из наших приложений Windows? Или вам нужно использовать «сокеты». Я в первую очередь ищу библиотеки или пример кода, который может легко удовлетворить мою потребность, я не хочу разрабатывать собственный TCP-протокол или что-то хардкор!

ответ

2

Для передачи файлов/данных вы можете использовать классы TcpClient/TcpListener, что является хорошим абстракцией по функциональности сокета grittier. Или вы можете просто использовать приложение в качестве HTTP-сервера, используя класс HttpListener, если это проще или более подходящим для вашего приложения.

Для обнаружения, если у вас есть центральный сервер; то вы можете подключить каждый клиент к серверу при запуске, зарегистрировать себя и получить список других онлайн-клиентов и их IP-адресов. Последующая связь может осуществляться непосредственно между клиентами.

Вариант этой схемы заключается в том, чтобы центральный сервер выступал в качестве прокси-сервера, через который проходит весь трафик между клиентами. Это было бы в основном полезно для преодоления проблем с брандмауэром или маршрутизацией, если клиенты не находятся в одной сети (так что это нежелательно для вашего сценария).

+0

ASP.Net классы? Я искал связь между приложениями Windows. –

+0

Что это значит? Ни один из классов, о которых я упоминаю, не относится к классам ASP.NET. – driis

2

Большая вещь о файлах и сокетов в C# является то, что они оба подвергаются как потоки. Копирование большого файла из одного потока в другой довольно просто:

byte[] data = new byte[1024]; 
while(true) { 
int bytesRead = filestream.read(data,0,data.Length); 
if (bytesRead==0) break; 
netstream.write(data,0,bytesRead); 
} 

Затем просто закройте сокет, когда закончите.

Если вы хотите отправить метаданные (имена файлов, размеры) или не хотите закрыть соединение, для этого вам нужен какой-то протокол. FTP использует два отдельных сокета (один для метаданных, один для данных, это называется внеполосной связью). Если вы находитесь в локальной сети без брандмауэров, это вполне приемлемо. С другой стороны, если вы хотите сделать интернет-трансляцию, получение одного порта открытым - задача довольно сложная, а две невыносимы. Если вы не слишком заботитесь о производительности, вы можете кодировать байты в кодировке base64, что гарантирует, что они находятся в пределах определенного байтового диапазона. С base64 вы можете разделить сообщения с символами новой строки или другими не-буквенно-цифровыми символами. Затем в первом сообщении укажите имя файла, размер или что-то еще, затем отправьте данные как второе сообщение, затем отправьте сообщение «это весь файл», чтобы клиент знал, что это сделано.

Другая тактика для сообщений - использование escape-последовательности. Например, возьмите свой байтовый поток и замените каждый экземпляр «\ 0» на «\ 0 \ 0». Теперь используйте '\ 0 \ 1', чтобы сигнализировать о конце сообщения, которое гарантировано не содержится в вашем сообщении данных. Декодируйте '\ 0 \ 0' назад на '\ 0' на принимающей стороне.Это хорошо работает в C, но я нахожу, что на практике цикл через каждый байт может быть медленнее, чем чтение целых буферов на C#.

Лучший способ - принять какой-то протокол адаптивной длины. Например, отправьте данные в куски определенного размера (скажем, 512 байт). Перед каждым фрагментом отправьте 32-битный int, представляющий размер блока через System.BitConverter. Так сообщения выглядеть следующим образом (на английском языке):

Here's 512 bytes: 
[data] 
Here's 512 bytes: 
[data] 
Here's 32 bytes: 
[data] 
Here's 4 bytes: 
That was the whole file 

Преимущество здесь состоит в том, что вы можете сделать копию/чтения буфера работают для вас (чтение 512 байт в то время), означает, что ваша пропускная способность ограничена вашей сетевой стек вместо вашего кода на C#. Клиент считывает 32-битный int с фиксированной длиной, который позволяет узнать размер буфера, который он должен использовать для следующего сегмента [data].

Вот код, чтобы писать сообщения вроде:

 logger.logger.debug("Sending message of length " + length); 
     byte[] clength = System.BitConverter.GetBytes(buffer.Length); 
     plaintextStream.Write(clength,0,clength.Length); 
     plaintextStream.Write(buffer,0,buffer.Length); 
     plaintextStream.Flush(); 

И вот какой-то код, чтобы прочитать их:

   byte[] intbuf = new byte[int_32_size]; 
     int offset = 0; 
     while (offset < int_32_size) 
     { 
      int read = 0; 

      read = d.plaintextStream.Read(intbuf,offset,int_32_size - offset); 
      offset += read; 

     } 
     int msg_size = System.BitConverter.ToInt32(intbuf,0); 
     //allocate a new buffer to fill the message 
     byte[] msg_buffer = new byte[msg_size]; 
     offset = 0; 
     while (offset < msg_size) 
     { 
      int read = 0; 

      read = d.plaintextStream.Read(msg_buffer,offset,msg_size - offset); 
      offset += read; 
     } 


     return msg_buffer;