How can a C# app easily communicate and transfer files on a network?

You can use System.Net.Sockets class to communicate and it have a method for sending file Socket.SendFile.

Update:
this is a good example for file sharing and sending file from C# help


The great thing about files and sockets in C# is that they're both exposed as streams. Copying a large file from one stream to another is pretty simple:

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

Then just close the socket when you're done.

If you want to send metadata (filenames, sizes) or don't want to close the connection, you need some sort of protocol to handle this. FTP uses two seperate sockets(one for metadata, one for data; this is called out-of-band communication). If you're on a LAN with no firewalls, that can be perfectly acceptable. On the other hand, if you want to do internet transfer, getting a single port open is a difficult-enough task, and two is unbearable. If you don't care too much about performance, you could encode the bytes in base64 encoding, which makes sure that they're within a certain byte range. With base64, you can seperate messages with newlines or other non-alphanumeric characters. Then in the first message include the filename, size, or whatever, then send the data as a second message, then send a "that's the whole file" message so the client knows it's done.

Another tactic for messages is using an escape sequence. For instance, take your bytestream and replace each instance of '\0' with '\0\0'. Now use '\0\1' to signal the end-of-message, which is guaranteed not to be contained in your data message. Decode the '\0\0' back to '\0' on the receiving end. This works well enough in C, but I find that, in practice, looping through each byte can be slower than reading whole buffers in C#.

The best way is to adopt some sort of adaptive-length protocol. For instance, send the data in chunks of a certain size (say 512 bytes). Before each chunk, send a 32bit int representing the size of the chunk via System.BitConverter. So messages look like this (english):

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

The advantage here is that you can make the copy/read buffers work for you (reading 512 bytes at a time), meaning your throughput is limited by your network stack instead of your C# code. The client reads the fixed-length 32-bit int that lets it know the size of the buffer it should use for the next [data] segment.

Here's some code to write messages like that:

        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();

And here's some code to read them:

               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;

For transferring the files / data, you can use the TcpClient/TcpListener classes, which is nice abstractions over the grittier socket functionality. Or, you could simply have the application as a HTTP server using the HttpListener class, if that is easier/more appropiate for your application.

For discovery, if you are able to have a central server; then you could have each client connect to the server at startup, to register itself and retrieve a list of other online clients and their IP's. Subsequent communication can then take place directly between the clients.

A variation of this scheme, is to let the central server act as a proxy, which all traffic between the clients flow through. This would be mostly helpful to overcome firewall or routing issues if the clients is not on the same network (so it's propably not needed for your scenario).