Here is some very basic code that logs in, gets a list of files, downloads a file, uploads a file, and then quits.
Hope it helps someone somewhere.
Written in NETMF 4.2 on a Cerberus board to connect over a LAN to a FileZilla Server. Assumes that the firewall is not blocking the static IP of the Cerb at all and that the user has read/write access.
using System;
using System.Net;
using System.Net.Sockets;
using Microsoft.SPOT.Net.NetworkInformation;
using System.Text;
using Microsoft.SPOT;
namespace AnotherFTPClientAttempt
{
// This program opens a connection to a FTP server at 192.168.1.43 using port 21
// It then logs in with 'myUserName' and 'myPassword'.
// Three commands are issued: NLST, RETR madeOnCPU.txt, and STOR madeOnMCU.txt
// The program then quits using the QUIT command and enters an endless loop.
//
// Debug information is printed to the output window. Almost no checks on returned
// strings/bytes written/bytes read/etc. are done. This is mostly a proof of
// concept. It has been tested using NETMF 4.2, a Cerberus board, a FileZilla
// server, all of which is running on a local area network. Note that the static
// IP (192.168.1.250) of the Cerberus had to be allowed in the inbound rules
// of the PC's firewall for any connection to be made.
public class Program
{
static string myIP = "192.168.1.250"; // Enter whatever static IP you want to use here
static string subnetMask = "255.255.255.0"; // I think this is a default/common mask
static string gatewayAddress = "192.168.1.1"; // I believe this needs to be the router IP, but could be wrong
static string dnsAddresses = "192.168.1.1"; // I believe this needs to be the router IP, but could be wrong
static byte[] myMAC = new byte[] { 0x00, 0x30, 0xFB, 0x87, 0xD2, 0x3C }; // Works for me! But not sure of its importance/significance
public static void Main()
{
Debug.Print("STARTING...");
InitializeNetworkStatic();
string rString = "";
string serverIP = "192.168.1.43"; // Change for your server's IP
int serverPort = 21; // Usually 21, but dependent on your server
Socket socketA = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
Socket socketB = null;
int passivePort = -1; // Used with socketB when using the data connection
rString = connectToServer(socketA, serverIP, serverPort);
//NetworkStream netStream = null;
//netStream = new NetworkStream(socketA); // Look up what a network stream does!
//Debug.Print("Don't forget to try stuff with the NetworkStream to see if it works better/easier!!!");
// Login to the server
sendToSocket(socketA, "USER myUserName\r\n");
rString = readFromSocket(socketA);
sendToSocket(socketA, "PASS myPassword\r\n");
rString = readFromSocket(socketA);
// List the directory using NLST
sendToSocket(socketA, "PASV\r\n");
rString = readFromSocket(socketA);
passivePort = parseForPasvPort(rString); // Server sends port to connect on
// Now we try to connect on the passive port
socketB = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socketB.Connect(new IPEndPoint(IPAddress.Parse(serverIP), passivePort));
sendToSocket(socketA, "NLST\r\n");
rString = readFromSocket(socketB); // READING FROM SOCKET B NOW!
socketB.Close();
// I already have a test file on my FTP server 'madeOnCPU.txt'
// Download this file next
sendToSocket(socketA, "TYPE A\r\n"); // Not sure if necessary, but FileZilla client does this
rString = readFromSocket(socketA);
sendToSocket(socketA, "PASV\r\n"); // Need new passive/data connection
rString = readFromSocket(socketA);
passivePort = parseForPasvPort(rString);
socketB = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socketB.Connect(new IPEndPoint(IPAddress.Parse(serverIP), passivePort));
sendToSocket(socketA, "RETR madeOnCPU.txt\r\n");
rString = readFromSocket(socketB);
socketB.Close();
// Create a file to upload to the server called madeOnMCU.txt
sendToSocket(socketA, "TYPE A\r\n"); // Not sure if necessary, but FileZilla client does this
rString = readFromSocket(socketA);
sendToSocket(socketA, "PASV\r\n"); // Need new passive/data connection
rString = readFromSocket(socketA);
passivePort = parseForPasvPort(rString);
socketB = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socketB.Connect(new IPEndPoint(IPAddress.Parse(serverIP), passivePort));
sendToSocket(socketA, "STOR madeOnMCU.txt\r\n");
rString = readFromSocket(socketA);
sendToSocket(socketB, "This was made on the MCU.");
socketB.Close();
// All done so send the QUIT command to log out
sendToSocket(socketA, "QUIT\r\n");
rString = readFromSocket(socketA);
socketA.Close();
// All done. Wait forever so we can read debug output
Debug.Print("DONE!!!!!");
while (true)
{
System.Threading.Thread.Sleep(100);
}
}
private static void InitializeNetworkStatic()
{
// Works for me, but is a copy/paste from GHI forum
// here: https://www.ghielectronics.com/community/forum/topic?id=10140&page=1
Debug.Print("Initializing network...");
NetworkInterface[] interfaces = NetworkInterface.GetAllNetworkInterfaces();
if (interfaces != null && interfaces.Length > 0)
{
NetworkInterface networkInterface = interfaces[0];
Boolean isDhcpWorked = false;
Debug.Print("Setting static IP...");
networkInterface.EnableStaticIP(myIP, subnetMask, gatewayAddress);
networkInterface.PhysicalAddress = myMAC;
networkInterface.EnableStaticDns(new[] { dnsAddresses });
Debug.Print("Network ready.");
Debug.Print(" IP Address: " + networkInterface.IPAddress);
Debug.Print(" Subnet Mask: " + networkInterface.SubnetMask);
Debug.Print(" Default Gateway: " + networkInterface.GatewayAddress);
Debug.Print(" DNS Server: " + networkInterface.DnsAddresses[0]);
}
else
{
Debug.Print("No network device found.");
}
}
public static string readFromSocket(Socket sock)
{
string receivedString = "";
int bytesRead = 0;
int bytesAvailToRead = 0;
byte[] buffer = null;
// DEBUG STUFF
int readCount = 0;
int pollCount = 0;
int waitCount = 0;
// The socket did not always have bytes immediately
// available to read, so I wait a bit until it is
// ready. This could be changed/shortened. Almost no
// testing was done here. to optimize.
while (waitCount < 10 && sock.Available == 0)
{
System.Threading.Thread.Sleep(100);
waitCount++;
}
while (sock.Available > 0)
{
if (sock.Poll(1000, SelectMode.SelectRead))
{
bytesAvailToRead = sock.Available;
buffer = new byte[bytesAvailToRead];
bytesRead += sock.Receive(buffer, bytesAvailToRead, SocketFlags.None);
receivedString += new string(Encoding.UTF8.GetChars(buffer));
readCount++;
}
else
{
pollCount++;
}
}
// DEBUG STUFF
Debug.Print("## DEBUG STATISTICS-----------");
Debug.Print("Waited " + waitCount + " times");
Debug.Print("Read " + receivedString);
Debug.Print("Took " + readCount + " Receive calls");
Debug.Print("Poll count = " + pollCount);
Debug.Print("----------------------------");
return receivedString;
}
public static void sendToSocket(Socket sock, string sendMe)
{
// Write it here
if (sock.Poll(1000, SelectMode.SelectWrite))
{
int numSent = sock.Send(Encoding.UTF8.GetBytes(sendMe));
Debug.Print("Sent " + numSent + " bytes");
}
else
{
Debug.Print("Poll said not ready to write");
}
}
public static string connectToServer(Socket sock, string ip, int port)
{
IPEndPoint ipep = new IPEndPoint(IPAddress.Parse(ip), port);
sock.Connect(ipep);
// Read welcome message and return
return readFromSocket(sock);
}
public static int parseForPasvPort(string s)
{
// Probably only works for FileZilla servers.
// There are suggestions online for how to read/parse
// for a passive port number online. For example,
// here: http://cr.yp.to/ftp/retr.html
int i, j;
i = s.IndexOf('(');
j = s.IndexOf(')');
string ip = s.Substring(i + 1, j - i - 1);
string[] pieces = ip.Split(',');
return System.Convert.ToInt32(pieces[pieces.Length - 2]) * 256 + System.Convert.ToInt32(pieces[pieces.Length - 1]);
}
}
}