一、FTP数据结构
二进制结构:文件中没有内部结构,一般被看作二进制流;
文件式结构:由许多记录组成的文件;
页面结构:由不同的索引页组成文件;
二、FTP数据传输模式
二进制模式:
在二进制结构中,发送方发送完数据后,会在关闭连接时标记EOF。
文件模式:
文件模式就是以文件结构的形式进行数据传输。
压缩模式:
三、与服务器的连接
FTP在与服务器连接时,需要用到二个端口:
端口21(FTP默认端口为21)作为控制连接端口,用于发送命令给服务器以及等待服务器响应;
端口20(任意有效端口号)作为数据传输端口,用来建立数据传输通道;
FYP客户端连接服务器有两种模式:
PORT模式:PORT为主动模式。需要向服务器提供一个IP地址和一个端口号
PASV模式: PASV为被动模式。服务器需要提供给客户一个IP地址和一个端口号
FTP常用命令:
1. open: 与服务器相连接;
2. send / put:上传文件;
3. get: 下载文件;
4. mget: 下载多个文件;
5. cd: 切换目录;
6. dir: 查看当前目录下的文件;
7. del: 删除文件;
8. bye / exit 退出
参考连接:http://blog.csdn.net/cv_yuippe/article/details/25319533
-------------------------------------------------------------------------
在编程中自定义几个封装函数:
发送命令函数MySockSend()
void CFTP_clientDlg::MySockSend(CString send_msg)
{
int sign = sock_client.Send(send_msg, send_msg.GetLength());
if ( SOCKET_ERROR == sign)
{
AfxMessageBox("数据发送失败");
return;
}
//将命令添加到ListBox上
CString show_msg = "命令:";
show_msg += send_msg;
m_listinfo.AddString(show_msg);
}
void CFTP_clientDlg::MySockRecv()
{
char buf_recv[128] = "";
int sign = sock_client.Receive(buf_recv,127);
if(SOCKET_ERROR == sign)
{
AfxMessageBox("数据接收失败!");
return;
}
//将信息显示在ListBox上
CString show_msg = "响应: ";
show_msg += buf_recv;
memset(buf_recv, strlen(buf_recv), NULL);
m_listinfo.AddString(show_msg);
}
被动模式PASV函数Pasv_mode()
BOOL CFTP_clientDlg::Pasv_mode()
{
//创建新的socket
if ( !sock_temp.Create() )
{
AfxMessageBox("sock_temp创建失败");
return FALSE;
}
CString send_msg; //专用于发送信息
//让服务器进入被动模式,命令:PASV
send_msg = "PASV\r\n";
MySockSend(send_msg);
//接收信息
char buf_recv[64] = "";
if ( SOCKET_ERROR == sock_client.Receive(buf_recv, 64) )
{
AfxMessageBox("数据接收失败!");
sock_temp.Close();
return FALSE;
}
//将响应信息添加到列表框
CString show_msg = "响应:";
show_msg += buf_recv;
m_listinfo.AddString(show_msg);
//解析返回的信息
CString parse_str = buf_recv;
int index_first = 0, index_mid = 0, index_end = 0;
//定义所需信息的位置
index_end = parse_str.Find(')');
index_mid = parse_str.ReverseFind(',');
index_first = parse_str.Find(',', index_mid - 4);
//获得端口号
char port_str[4] = "";
int i,j=0;
for (i = index_first + 1; i < index_mid; i++)
{
port_str[j++] = parse_str.GetAt(i);
}
int port_int = atoi(port_str);
j = 0;
memset(port_str, 0, 4);
for (i = index_mid + 1; i < index_end; i++)
{
port_str[j++] = parse_str.GetAt(i);
}
//计算得出新开的端口号
port_int = port_int*256 + atoi(port_str);
//用新的sock连接服务器
if ( !sock_temp.Connect(m_host, port_int) )
{
AfxMessageBox("sock_temp连接服务器失败");
sock_temp.Close();
return FALSE;
}
return TRUE;
}
解析函数Parse_list()
void CFTP_clientDlg::Parse_list()
{
//用新的socket接收文件信息
char filelist[1024] = "";
if ( SOCKET_ERROR == sock_temp.Receive(filelist, 1024) )
{
AfxMessageBox("数据接收失败");
return;
}
CString parselist = filelist;
//获取字符串的长度
long len = parselist.GetLength();
//解析获取所有的文件名
char filename[32] = "";
int index_rn = parselist.Find("\r\n"); //第一行信息结束的位置
int i,j=0;
while ( len - 1 != index_rn + 1) //获取的长度不等于第一个"\r\n"则去查找
{
//获取文件名的起始位置
for ( i = index_rn - 1; parselist.GetAt(i) != ' '; i--);
//获取文件名
for (i = i + 1; i < index_rn; i++)
{
filename[j++] = parselist.GetAt(i);
}
j = 0;
//找到下一行结束的位置
index_rn = parselist.Find("\r\n", index_rn + 2);
//忽略"."和".."文件
if ( filename[0] == '.' )
{
memset(filename, 0, 32);
continue;
}
//将文件名添加到文件列表框中
m_listfile.AddString(filename);
memset(filename, 0, 32);
}
//获取最后一个文件名
//获取文件名起始位置
for ( i = index_rn - 1; parselist.GetAt(i) != ' '; i--);
for (i = i + 1; i < index_rn; i++)
{
filename[j++] = parselist.GetAt(i);
}
if (filename[0] == '.')
{
return;
}
m_listfile.AddString(filename);
}
总结:
IDE:vs2012 + win7,在返回的响应值由char类型保存,如果用wchar则会出现乱码,这是因为在网络传输中还是以单字节为主。
本实例源代码