locked
Send and receive file using System.Net.Sockets.Socket in C# RRS feed

  • Question

  • Hi, 

    I am trying to send a file from a tcp socket server to a client, I've found how to use the SendFile method to send from the server, but there is no additional method for receiving. So, 

    how to Receive a file when sent with the SendFile method?

    PS. Here is the SendFile method I've found:

    http://msdn.microsoft.com/en-us/library/sx0a40c2.aspx

    // Establish the local endpoint for the socket.
    IPHostEntry ipHost = Dns.GetHostEntry(Dns.GetHostName());
    IPAddress  ipAddr = ipHost.AddressList[0];
    IPEndPoint ipEndPoint = new IPEndPoint(ipAddr, 11000);
    
    // Create a TCP socket.
    Socket client = new Socket(AddressFamily.InterNetwork,
            SocketType.Stream, ProtocolType.Tcp);
    
    // Connect the socket to the remote endpoint.
    client.Connect(ipEndPoint);
    
    // There is a text file test.txt located in the root directory. 
    string fileName = "C:\\test.txt";
    
    // Send file fileName to remote device
    Console.WriteLine("Sending {0} to the host.", fileName);
    client.SendFile(fileName);
    
    // Release the socket.
    client.Shutdown(SocketShutdown.Both);
    client.Close();

    PS. will the Socket.SendFile Method be able to handle files as big as 6~15G?

    Thanks


    • Edited by smetah Monday, December 17, 2012 9:35 PM
    • Moved by Bob Shen Tuesday, December 18, 2012 4:58 AM (From:Visual C# General)
    Monday, December 17, 2012 9:26 PM

Answers

  • TCP is a low level transport protocol.  There are many application level network protocols that uses TCP like FTP , and HTTP.  TCP has the following features:

    1) Have message is achnowledged by the far end so many say that TCP is reliable.  UDP doesn't have the acks.  If a datagram doesn't get ACK it is resent.

    2) TCP Data is broken up into datagrams around 1500 bytes.  HTTP chunks are another layer of partitioning data ontop of TCP so the receving Browser can start processing the received data before the entire webpage is downloaded.

    3) the 1500 byte packets may get routed through different servers so the receiving end of a TCP connection must reorder the packets.  This is done by the Ethernet Driver.

    The Net Library doesnh't use the Winsock TransmitFile API internally.  There were issues with Winsock API and the Net Library decided a long time ago to write there own library for TCP.

    The end fo file can be handled two ways.  If you have a text file, you can add a '\0' character at the end of the file and then read until you get the '\0'.  You can use any character as the end of file as long as the character isn't in the data itself.  If you have binary data then the best method is to add a 4 byte count (or 8 for very large files) at the beginning of the message and then read until the number of bytes is received.  You can also add the byte count for text files instead of an end of file.


    jdweng

    • Marked as answer by smetah Thursday, December 20, 2012 2:07 PM
    Tuesday, December 18, 2012 3:04 PM
  • All the send file does is combine a few  methods together into one method.  It is a blocking (synchronous) send method which opens a file, creates a stream, and then sends all the data in th e file to the client.  The client can't tell the differences if the data is sent using Send(), SendFile(), or AsyncSend().

    jdweng

    • Marked as answer by smetah Thursday, December 20, 2012 2:06 PM
    Tuesday, December 18, 2012 8:28 AM
  • Try this

    string LocalHostName = Dns.GetHostName();
                IPHostEntry LocalHostIPEntry = Dns.GetHostEntry(LocalHostName);
                IPAddress LocalHostIP = LocalHostIPEntry.AddressList[0];
                TcpListener list = new TcpListener(LocalHostIP, 1234);
                string IP = ((IPEndPoint)list.Server.RemoteEndPoint).ToString();


    jdweng

    • Marked as answer by smetah Thursday, December 20, 2012 3:25 PM
    Thursday, December 20, 2012 2:53 PM
  • string

    remoteIP = ((IPEndPoint)clientSocket.RemoteEndPoint).ToString();

    jdweng

    • Marked as answer by smetah Thursday, December 20, 2012 6:44 PM
    Thursday, December 20, 2012 5:24 PM

All replies

  • You can use any TCP receive method to get the data.  YOu also need to develope an higher level application protocol for sending data. th equestion you need to ask is how does the the client know that this data being sent is a file and that the connection is going to close after the file is sent.  You have a few problems with your application level protocol.

    Thre must be a master/slave relationship between the client and server.  Te client is the master that sends commands to the server and the server is a slave which processes the conmands.  For the server to send the file the client need to send a command requesting the file. The server can't jsut send a file without the client expecting a file.

    You also have a problem with the client closing the connection at the end of the file.  the conection close should only be done from one end of the connection after all the data is recevied.  A binary should be sent with a byte count added a the beginning of the file.  A text file cxan be sent eith er by adding a byte count to the beginning of the files transfer or ending the text data with a '\0'.  This is how I would impliment a download of a text file.

    Client                                                                Server

    Send command : download file abc  ---->         Process command

    Read data until '\0' character           <----          Send file  adding a '\0' character to the end of file.

    Send command to close connection ------>        Process command and close connection

    Wait for Asyn close event.  Exit Application        Exit Application


    jdweng

    Monday, December 17, 2012 11:27 PM
  • A binary should be sent with a byte count added a the beginning of the file.  A text file cxan be sent eith er by adding a byte count to the beginning of the files transfer or ending the text data with a '\0'. . . 

    Thanks Joel, 

    What you described is how to coin the higher level application protocol all by ourselves. However, since the file sending part is taken care of by Socket.SendFile, I'm wondering what's the corresponding receiving end has to do in order to comply with the protocol used by Socket.SendFile. 

    Thanks

    Monday, December 17, 2012 11:33 PM
  • Hi smetah,

    According to your description, I'd like to move this thread to Network Class Library (System.Net)Forum for better support, where more experts live.
     
    Thanks for your understanding.


    Bob Shen
    MSDN Community Support | Feedback to us
    Develop and promote your apps in Windows Store
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Tuesday, December 18, 2012 4:57 AM
  • All the send file does is combine a few  methods together into one method.  It is a blocking (synchronous) send method which opens a file, creates a stream, and then sends all the data in th e file to the client.  The client can't tell the differences if the data is sent using Send(), SendFile(), or AsyncSend().

    jdweng

    • Marked as answer by smetah Thursday, December 20, 2012 2:06 PM
    Tuesday, December 18, 2012 8:28 AM
  • I'd like to move this thread to Network Class Library (System.Net)Forum for better support, where more experts live.

    Thanks. That's very helpful.

    Tuesday, December 18, 2012 2:20 PM
  • . . . and then sends all the data in th e file to the client. 

    Just to be sure, the Socket.SendFile Method is able to handle big files, by sending the file data chunk by chunk, right?

    Oh, another question, if I use the Socket.SendFile Method, how should I handle the case of at the end of the file? I can't use a byte count added a the beginning of the file, nor can I add trailing  '\0' because the file might not always text data. what's your suggestion?

    Thanks

    Tuesday, December 18, 2012 2:27 PM
  • Also, will the Socket.SendFile Method use the Winsock TransmitFile API internally? which is documented as:

    http://msdn.microsoft.com/en-us/library/ms740565.aspx 

    [quote]

    The TransmitFile function transmits file data over a connected socket handle. This function uses the operating system's cache manager to retrieve the file data, and provides high-performance file data transfer over sockets.

    [/quote]

    Thanks

    Tuesday, December 18, 2012 2:47 PM
  • TCP is a low level transport protocol.  There are many application level network protocols that uses TCP like FTP , and HTTP.  TCP has the following features:

    1) Have message is achnowledged by the far end so many say that TCP is reliable.  UDP doesn't have the acks.  If a datagram doesn't get ACK it is resent.

    2) TCP Data is broken up into datagrams around 1500 bytes.  HTTP chunks are another layer of partitioning data ontop of TCP so the receving Browser can start processing the received data before the entire webpage is downloaded.

    3) the 1500 byte packets may get routed through different servers so the receiving end of a TCP connection must reorder the packets.  This is done by the Ethernet Driver.

    The Net Library doesnh't use the Winsock TransmitFile API internally.  There were issues with Winsock API and the Net Library decided a long time ago to write there own library for TCP.

    The end fo file can be handled two ways.  If you have a text file, you can add a '\0' character at the end of the file and then read until you get the '\0'.  You can use any character as the end of file as long as the character isn't in the data itself.  If you have binary data then the best method is to add a 4 byte count (or 8 for very large files) at the beginning of the message and then read until the number of bytes is received.  You can also add the byte count for text files instead of an end of file.


    jdweng

    • Marked as answer by smetah Thursday, December 20, 2012 2:07 PM
    Tuesday, December 18, 2012 3:04 PM
  • Thanks a lot Joel. 

    I think that answers all my questions. 

    Please allow the question to be opened for two more days in case someone else has more say to it, then I'll mark it answered.

    Thanks

    Tuesday, December 18, 2012 3:14 PM
  • Oh, one more question, 

    After 

    listener.Accept();

    how can I tell where the client is connecting from?

    Thanks

    Thursday, December 20, 2012 2:27 PM
  • Try this

    string LocalHostName = Dns.GetHostName();
                IPHostEntry LocalHostIPEntry = Dns.GetHostEntry(LocalHostName);
                IPAddress LocalHostIP = LocalHostIPEntry.AddressList[0];
                TcpListener list = new TcpListener(LocalHostIP, 1234);
                string IP = ((IPEndPoint)list.Server.RemoteEndPoint).ToString();


    jdweng

    • Marked as answer by smetah Thursday, December 20, 2012 3:25 PM
    Thursday, December 20, 2012 2:53 PM
  • Thanks, really appreciate all your helps. 
    Thursday, December 20, 2012 3:25 PM
  • Hmm, how to apply that to System.Net.Sockets.Socket, instead of TcpListener?

    I will get exception error if I unleash the listener.RemoteEndPoint.ToString(); from the comment. The exception is saying something like no connection and no address supplied. 

    PS. How can I get the remote port as well?

    string remotePort = listener.RemoteEndPoint...?

    Thanks

                IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName());
                IPAddress ipAddress = ipHostInfo.AddressList[0];
                ipAddress = IPAddress.Parse("127.0.0.1");
                IPEndPoint localEndPoint = new IPEndPoint(ipAddress, port);
    
                Socket listener =
                        new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                listener.Bind(localEndPoint);
                listener.Listen(port);
    
                Socket clientSocket = listener.Accept();
                string remoteIP = ""; // listener.RemoteEndPoint.ToString();


    • Edited by smetah Thursday, December 20, 2012 3:51 PM
    Thursday, December 20, 2012 3:48 PM
  • string

    remoteIP = ((IPEndPoint)clientSocket.RemoteEndPoint).ToString();

    jdweng

    • Marked as answer by smetah Thursday, December 20, 2012 6:44 PM
    Thursday, December 20, 2012 5:24 PM
  • Splendid! Thanks a lot Joel. 
    Thursday, December 20, 2012 6:44 PM