已经好久没有写过博客进行分享了。具体原因,在以后说。

  这几天在了解FTP协议,准备任务是写一个FTP客户端程序。直接上干货了。

0.了解FTP作用

  就是一个提供一个文件的共享协议。

1.了解FTP协议

  FTP有指令和响应码。FTP 控制帧即指 TELNET 交换信息,包含 TELNET 命令和选项。然而,大多数 FTP 控制帧是简单的 ASCII 文本,可以分为 FTP 命令或 FTP 消息。 FTP 消息是对 FTP 命令的响应,它由带有解释文本的应答代码构成。

  像这种利用交换信息来进行简单的控制,这种协议,还真的很好玩的说。 命令与响应码部分信息如下

  

  

2. 安装一个FTP服务器

  我们先安装一个FTP服务器,用于测试,这里是用FileZilla Server作为FTP服务器。

  启动后,增加一个用户user/user

3.FTP客户端源代码讲解

  下面这个是FTPAPI.h文件

 #ifndef FTPAPI_H_INCLUDED
#define FTPAPI_H_INCLUDED #include <stdio.h>
#include <winsock2.h> SOCKET socket_connect(char *host, int port);
SOCKET connect_server(char *host, int port);
int ftp_sendcmd_re(SOCKET sock, char *cmd, char *re_buf, ssize_t *len);
int ftp_sendcmd(SOCKET sock, char *cmd);
int login_server(SOCKET sock, char *user, char *pwd);
void socket_close(int c_sock); /**********可用命令*********/
SOCKET ftp_connect(char *host, int port, char *user, char *pwd); //连接到服务器
int ftp_quit(SOCKET sock); //断开连接
int ftp_type(SOCKET sock, char mode); //设置FTP传输类型
int ftp_cwd(SOCKET sock, char *path); //更改工作目录
int ftp_cdup(SOCKET sock); //回到上级目录
int ftp_mkd(SOCKET sock, char *path); //创建目录
SOCKET ftp_pasv_connect(SOCKET c_sock); //连接到PASV接口
int ftp_list(SOCKET c_sock, char *path, char **data, int *data_len); //列出FTP工作空间的所有目录
int ftp_deletefolder(SOCKET sock, char *path); //删除目录
int ftp_deletefile(SOCKET sock, char *filename); //删除文件
int ftp_renamefile(SOCKET sock, char *s, char *d); //修改文件/目录&移动文件/目录
int ftp_server2local(SOCKET c_sock, char *s, char *d, int * size); //从服务器复制文件到本地 RETR
int ftp_local2server(SOCKET c_sock, char *s, char *d, int * size); //从本地复制文件到服务器 STOR
int ftp_recv(SOCKET sock, char *re_buf, ssize_t *len); //获取响应码 #endif // FTPAPI_H_INCLUDED

  下面这个是FTPResponseCode.h 文件 是对应答码简单的描述

 #ifndef FTPRESPONSECODE_H_INCLUDED
#define FTPRESPONSECODE_H_INCLUDED #define FTP_SUCCESS 200 //成功
#define FTP_SERVICE_READY 220 //服务器就绪
#define FTP_LOGIN_SUCCESS 230 //登录因特网服务器
#define FTP_FILE_ACTION_COMPLETE 250 //文件行为完成
#define FTP_FILE_CREATED 257 //文件创建成功
#define FTP_PASSWORD_REQUIREd 331 //要求密码
#define FTP_LOGIN_PASSWORD_INCORRECT 530 //用户密码错误 #endif // FTPRESPONSECODE_H_INCLUDED

  下面这些是FTPAPI.cpp文件的函数代码

  创建一个socket连接并返回socket套接字 socket_connect

 /**
* 作用: 创建一个Socket并返回.
* 参数: IP或域名, 端口
* 返回值: Socket套接字
* */
SOCKET socket_connect(char *host, int port)
{
int i=;
//初始化 Socket dll
WSADATA wsaData;
WORD socketVersion = MAKEWORD(,);
if(WSAStartup(socketVersion, &wsaData))
{
printf("Init socket dll error!");
exit();
} struct hostent * server = gethostbyname(host);
if(!server)
return -;
unsigned char ch[];
char ip[];
//一个hostname 可以对应多个ip
while(server->h_addr_list[i]!=NULL)
{
memcpy(&ch,server->h_addr_list[i],);
sprintf(ip,"%d.%d.%d.%d",ch[],ch[],ch[],ch[]);
//printf("%s\n",ip);
i++;
} //创建Socket
SOCKET s = socket(AF_INET, SOCK_STREAM, ); //TCP socket
if(SOCKET_ERROR == s)
{
printf("Create Socket Error!");
exit();
}
//设置超时连接
int timeout = ; //复杂的网络环境要设置超时判断
int ret = setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(timeout));
ret = setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,sizeof(timeout));
//指定服务器地址
struct sockaddr_in address;
address.sin_family = AF_INET;
address.sin_addr.S_un.S_addr = inet_addr(ip);
address.sin_port = htons((unsigned short)port);
//连接
if(SOCKET_ERROR == connect(s,(LPSOCKADDR)&address,sizeof(address)))
{
printf("Can Not Connect To Server IP!\n");
exit();
}
return s;
}

  连接到一个ftp服务器 connect_server

 /**
* 作用: 连接到一个FTP服务器,返回socket
* 参数: IP或域名, 端口
* 返回值: Socket套接字
* */
SOCKET connect_server(char *host, int port)
{
SOCKET ctrl_sock;
char buf[BUFSIZE];
int result;
ssize_t len; ctrl_sock = socket_connect(host,port);
if(- == ctrl_sock)
{
return -;
}
while((len = recv(ctrl_sock, buf, BUFSIZE, )) > )
{
//len = recv(ctrl_sock, buf, BUFSIZE, 0);
buf[len]=;
printf("%s\n",buf); //220-FileZilla Server version 0.9.43 beta
}
sscanf(buf, "%d", &result); if(FTP_SERVICE_READY != result)
{
printf("FTP Not ready, Close the socet.");
closesocket(ctrl_sock); //关闭Socket
return -;
}
return ctrl_sock;
}

  send发送命令,并返回recv结果 ftp_sendcmd_re

 /**
* 作用: send发送命令,并返回recv结果
* 参数: SOCKET,命令,命令返回码-命令返回描述,命令返回字节数
* 返回值: 0 表示发送成功 -1表示发送失败
* */
int ftp_sendcmd_re(SOCKET sock, char *cmd, char *re_buf, ssize_t *len)
{
char buf[BUFSIZE];
ssize_t r_len;
if(send(sock, cmd, strlen(cmd), ) == -)
{
return -;
}
r_len = recv(sock, buf, BUFSIZE, );
if(r_len < )
return -;
buf[r_len]=;
if(NULL != len)
*len = r_len;
if(NULL != re_buf)
sprintf(re_buf, "%s", buf);
return ;
}

  send发送命令 ftp_sendcmd

 /**
* 作用: send发送命令
* 参数: SOCKET,命令
* 返回值: FTP响应码
* */
int ftp_sendcmd(SOCKET sock, char *cmd)
{
char buf[BUFSIZE];
int result;
ssize_t len;
printf("FTP Client: %s", cmd);
result = ftp_sendcmd_re(sock, cmd, buf, &len);
printf("FTP Server: %s", buf);
if( == result)
{
sscanf(buf, "%d", &result);
}
return result;
}

  登录FTP服务器 login_server

 /**
* 作用: 登录FTP服务器
* 参数: SOCKET套接字,明文用户名,明文密码
* 返回值: 0 表示登录成功 -1 表示登录失败
* */
int login_server(SOCKET sock, char *user, char *pwd)
{
char buf[BUFSIZE];
int result;
sprintf(buf, "USER %s\r\n", user);
//这里要对socket进行阻塞
int timeout=;
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,sizeof(timeout));
result = ftp_sendcmd(sock, buf);
if(FTP_LOGIN_SUCCESS == result) //直接登录
return ;
else if(FTP_PASSWORD_REQUIREd == result) //需要密码
{
sprintf(buf, "PASS %s\r\n", pwd);
result = ftp_sendcmd(sock, buf);
if(FTP_LOGIN_SUCCESS == result)
{
return ;
}
else //530 密码错误
{
return -;
}
}
else
{
return -;
}
}

  winsock使用后,要调用WSACleanup函数关闭网络设备 socket_close

 /**
* 作用: winsock使用后,要调用WSACleanup函数关闭网络设备,以便释放其占用的资源
* 参数: SOCKET
* 返回值: 无
* */
void socket_close(int c_sock)
{
WSACleanup();
}

  连接到FTP服务器 ftp_connect

 /**
* 作用: 连接到FTP服务器
* 参数: hostname或IP,端口,用户名,密码
* 返回值: 已连接到FTP服务器的SOCKET -1 表示登录失败
* */
SOCKET ftp_connect(char *host, int port, char *user, char *pwd)
{
SOCKET sock;
sock = connect_server(host, port);
if(- == sock)
{
return -;
}
if(- == login_server(sock, user, pwd))
{
closesocket(sock);
return -;
}
return sock;
}

  断开FTP服务器 ftp_quit

 /**
* 作用: 断开FTP服务器
* 参数: SOCKET
* 返回值: 成功断开状态码
* */
int ftp_quit(SOCKET sock)
{
int result = ;
result = ftp_sendcmd(sock, "QUIT\r\n");
closesocket(sock);
socket_close(sock);
return result;
}

  设置FTP传输类型 A:ascii I:Binary  ftp_type

 /**
* 作用: 设置FTP传输类型 A:ascii I:Binary
* 参数: SOCkET,类型
* 返回值: 0 表示成功 -1 表示失败
* */
int ftp_type(SOCKET sock, char mode)
{
char buf[BUFSIZ];
sprintf(buf,"TYPE %c\r\n", mode);
if(FTP_SUCCESS != ftp_sendcmd(sock, buf))
return -;
else
return ;
}

  更改工作目录 ftp_cwd

 /**
* 作用: 更改工作目录
* 参数: SOCKET,工作目录
* 返回值: 0 表示成功 -1 表示失败
* */
int ftp_cwd(SOCKET sock, char *path)
{
char buf[BUFSIZE];
int result;
sprintf(buf, "CWD %s\r\n", path);
result = ftp_sendcmd(sock, buf);
if(FTP_FILE_ACTION_COMPLETE != result) //250 文件行为完成
return -;
else
return ;
}

  回到上级目录 ftp_cdup

 /**
* 作用: 回到上级目录
* 参数: SOCKET
* 返回值: 0 正常操作返回 result 服务器返回响应码
* */
int ftp_cdup(SOCKET sock)
{
int result;
result = ftp_sendcmd(sock, "CDUP\r\n");
if(FTP_FILE_ACTION_COMPLETE == result || FTP_SUCCESS == result)
return ;
else
return result;
}

  创建目录 ftp_mkd

 /**
* 作用: 创建目录
* 参数: SOCKET,文件目录路径(可相对路径,绝对路径)
* 返回值: 0 正常操作返回 result 服务器返回响应码
* */
int ftp_mkd(SOCKET sock, char *path)
{
char buf[BUFSIZE];
int result;
sprintf(buf, "MKD %s\r\n", path);
result = ftp_sendcmd(sock, buf);
if(FTP_FILE_CREATED != result) //257 路径名建立
return result; //550 目录已存在
else
return ;
}

  连接到PASV接口 ftp_pasv_connect

 /**
* 作用: 连接到PASV接口
* PASV(被动)方式的连接过程是:
* 客户端向服务器的FTP端口(默认是21)发送连接请求,
* 服务器接受连接,建立一条命令链路。
* 参数: 命令链路SOCKET cmd-socket
* 返回值: 数据链路SOCKET raw-socket -1 表示创建失败
* */
SOCKET ftp_pasv_connect(SOCKET c_sock)
{
SOCKET r_sock;
int send_result;
ssize_t len;
int addr[]; //IP*4+Port*2
char buf[BUFSIZE];
char result_buf[BUFSIZE]; //设置PASV被动模式
memset(buf,sizeof(buf),);
sprintf(buf, "PASV\r\n");
send_result = ftp_sendcmd_re(c_sock, buf, result_buf, &len);
if(send_result == )
{
sscanf(result_buf, "%*[^(](%d,%d,%d,%d,%d,%d)",
&addr[],&addr[],&addr[],&addr[],
&addr[],&addr[]);
} //连接PASV端口
memset(buf, sizeof(buf), );
sprintf(buf, "%d.%d.%d.%d",addr[],addr[],addr[],addr[]);
r_sock = socket_connect(buf,addr[]*+addr[]);
if(- == r_sock)
return -;
return r_sock;
}

  列出FTP工作空间的所有目录 ftp_list

 /**
* 作用: 列出FTP工作空间的所有目录
* 参数: 命令链路SOCKET,工作空间,列表信息,列表信息大小
* 返回值: 0 表示列表成功 result>0 表示其他错误响应码 -1 表示创建pasv错误
* */
int ftp_list(SOCKET c_sock, char *path, char **data, int *data_len)
{
SOCKET r_sock;
char buf[BUFSIZE];
int send_re;
int result;
ssize_t len,buf_len,total_len; //连接到PASV接口
r_sock = ftp_pasv_connect(c_sock);
if(- == r_sock)
{
return -;
}
//发送LIST命令
memset(buf,sizeof(buf),);
sprintf(buf, "LIST %s\r\n", path);
send_re = ftp_sendcmd(c_sock, buf);
if(send_re >= || send_re == )
return send_re;
len=total_len=;
buf_len=BUFSIZE;
char *re_buf = (char *)malloc(buf_len);
while( (len = recv(r_sock,buf,BUFSIZE,)) > )
{
if(total_len+len > buf_len)
{
buf_len *= ;
char *re_buf_n = (char *)malloc(buf_len);
memcpy(re_buf_n, re_buf, total_len);
free(re_buf);
re_buf = re_buf_n;
}
memcpy(re_buf+total_len, buf, len);
total_len += len;
}
closesocket(r_sock); //向服务器接收返回值
memset(buf, sizeof(buf), );
len = recv(c_sock, buf, BUFSIZE, );
buf[len] = ;
sscanf(buf, "%d", &result);
if(result != )
{
free(re_buf);
return result;
}
*data = re_buf;
*data_len = total_len;
return ;
}

  删除目录 ftp_deletefolder

 /**
* 作用: 删除目录
* 参数: 命令链路SOCKET,路径目录
* 返回值: 0 表示列表成功 result>0 表示其他错误响应码
* */
int ftp_deletefolder(SOCKET sock, char *path)
{
char buf[BUFSIZE];
int result;
sprintf(buf,"RMD %s\r\n", path);
result = ftp_sendcmd(sock, buf);
if(FTP_FILE_ACTION_COMPLETE != result)
{
//550 Directory not empty.
//550 Directory not found.
return result;
}
return ;
}

  删除文件 ftp_deletefile

 /**
* 作用: 删除文件
* 参数: 命令链路SOCKET,路径文件(相对/绝对)
* 返回值: 0 表示列表成功 result>0 表示其他错误响应码
* */
int ftp_deletefile(SOCKET sock, char *filename)
{
char buf[BUFSIZE];
int result;
sprintf(buf, "DELE %s\r\n", filename);
result = ftp_sendcmd(sock, buf);
if(FTP_FILE_ACTION_COMPLETE != ) //250 File deleted successfully
{
//550 File not found.
return result;
}
return ;
}

  修改文件名&移动目录 ftp_renamefile

 /**
* 作用: 修改文件名&移动目录
* 参数: 命令链路SOCKET,源地址,目的地址
* 返回值: 0 表示列表成功 result>0 表示其他错误响应码
* */
int ftp_renamefile(SOCKET sock, char *s, char *d)
{
char buf[BUFSIZE];
int result;
sprintf(buf, "RNFR %s\r\n", s);
result = ftp_sendcmd(sock, buf);
if( != result) //350 文件行为暂停,因为要进行移动操作
return result;
sprintf(buf, "RNTO %s\r\n", d);
result = ftp_sendcmd(sock, buf);
if(FTP_FILE_ACTION_COMPLETE != result)
{
return result;
}
return ;
}

  从服务器复制文件到本地 RETR  ftp_server2local

 /**
* 作用: 从服务器复制文件到本地 RETR
* 参数: SOCKET,源地址,目的地址,文件大小
* 返回值: 0 表示列表成功 result>0 表示其他错误响应码
* -1:文件创建失败 -2 pasv接口错误
* */
int ftp_server2local(SOCKET c_sock, char *s, char *d, int * size)
{
SOCKET d_sock;
ssize_t len,write_len;
char buf[BUFSIZ];
int result;
*size=;
//打开本地文件
FILE * fp = fopen(d, "wb");
if(NULL == fp)
{
printf("Can't Open the file.\n");
return -;
}
//设置传输模式
ftp_type(c_sock,'I'); //连接到PASV接口 用于传输文件
d_sock = ftp_pasv_connect(c_sock);
if(- == d_sock)
{
fclose(fp); //关闭文件
return -;
} //发送RETR命令
memset(buf, sizeof(buf), );
sprintf(buf, "RETR %s\r\n", s);
result = ftp_sendcmd(c_sock, buf);
// 150 Opening data channel for file download from server of "xxxx"
if(result >= || result == ) //失败可能是没有权限什么的,具体看响应码
{
fclose(fp);
return result;
} //开始向PASV读取数据(下载)
memset(buf, sizeof(buf), );
while((len = recv(d_sock, buf, BUFSIZE, )) > )
{
write_len = fwrite(&buf, len, , fp);
if(write_len != ) //写入文件不完整
{
closesocket(d_sock); //关闭套接字
fclose(fp); //关闭文件
return -;
}
if(NULL != size)
{
*size += write_len;
}
}
//下载完成
closesocket(d_sock);
fclose(fp); //向服务器接收返回值
memset(buf, sizeof(buf), );
len = recv(c_sock, buf, BUFSIZE, );
buf[len] = ;
printf("%s\n",buf);
sscanf(buf, "%d", &result);
if(result >= )
{
return result;
}
//226 Successfully transferred "xxxx"
return ;
}

  从本地复制文件到服务器 STOR ftp_local2server

 /**
* 作用: 从本地复制文件到服务器 STOR
* 参数: SOCKET,源地址,目的地址,文件大小
* 返回值: 0 表示列表成功 result>0 表示其他错误响应码
* -1:文件创建失败 -2 pasv接口错误
* */
int ftp_local2server(SOCKET c_sock, char *s, char *d, int * size)
{
SOCKET d_sock;
ssize_t len,send_len;
char buf[BUFSIZE];
FILE * fp;
int send_re;
int result;
//打开本地文件
fp = fopen(s, "rb");
if(NULL == fp)
{
printf("Can't Not Open the file.\n");
return -;
}
//设置传输模式
ftp_type(c_sock, 'I');
//连接到PASV接口
d_sock = ftp_pasv_connect(c_sock);
if(d_sock == -)
{
fclose(fp);
return -;
} //发送STOR命令
memset(buf, sizeof(buf), );
sprintf(buf, "STOR %s\r\n", d);
send_re = ftp_sendcmd(c_sock, buf);
if(send_re >= || send_re == )
{
fclose(fp);
return send_re;
} //开始向PASV通道写数据
memset(buf, sizeof(buf), );
while( (len = fread(buf, , BUFSIZE, fp)) > )
{
send_len = send(d_sock, buf, len, );
if(send_len != len)
{
closesocket(d_sock);
fclose(fp);
return -;
}
if(NULL != size)
{
*size += send_len;
}
}
//完成上传
closesocket(d_sock);
fclose(fp); //向服务器接收响应码
memset(buf, sizeof(buf), );
len = recv(c_sock, buf, BUFSIZE, );
buf[len] = ;
sscanf(buf, "%d", &result);
if(result >= )
{
return result;
}
return ;
}

  获取一行响应码 ftp_recv

 /**
* 作用: 获取一行响应码
* 参数:
* 返回值:
* */
int ftp_recv(SOCKET sock, char *re_buf, ssize_t *len)
{
char buf[BUFSIZE];
ssize_t r_len;
int timeout = ;
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout));
r_len = recv(sock, buf, BUFSIZE, );
timeout = ;
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout));
if(r_len < )
return -;
buf[r_len]=;
if(NULL != len)
*len = r_len;
if(NULL != re_buf)
sprintf(re_buf, "%s", buf);
return ;
}

4.测试ftp客户端

  下载文件到本地

     SOCKET s = ftp_connect("127.0.0.1",,"user","user"); //登录到FTP服务器
int ret = ftp_server2local(s,"user/user.zip","bin.zip",&size); //在FTP服务器获取文件
ftp_quit(s); //退出FTP服务器

  上传文件到服务器

     SOCKET s = ftp_connect("127.0.0.1",,"user","user"); //登录到FTP服务器
int ret = ftp_local2server(s,"user/user.zip","bin.zip",&size); //发送文件到FTP服务器
ftp_quit(s); //退出FTP服务器

  下面这个是服务器的日志信息

  

  下面这个是程序打印的调试信息

  

5.后话

  到这里这个简单的ftp库就可以实现绝大部分的客户端功能了,但是这里面有一个问题,就是ftp是明文传输用户名/密码的,如果ftp上的文件比较重要的话,那么就有点问题了。当然这个不是本次的关注点,本次主要是了解ftp协议,还有从代码中了解这种交换控制命令的方法是一种很不错的技术手段,虽然这种方法已经是好多年前的,不安全,也过时了。但还是有可学的地方。

6.附录

  下面这个附录是利用wireshark进行本地网络抓包测试。

1、抓包,要看部署点,在路由器、交换机等设备上做端口镜像、或分光口,或是接HUB、TAP等设备就可以直接获得通过这些口的报文。
2、抓包,也可在以局域网部署相关的网管软件或黑客工具(比如cain),可以用arp骗方式,让你的数据先发送到监控机上,然后再转发走。。这样你的数据就。。

建议:
1、建议在电脑上打开ARP防护功能
2、在使用中尽量使用加密传输的工具,比如SSH、SSL、QQ一类的东西。可避免一些危害.

  注意wireshark是不能抓取本地回环地址的数据包的,所以我以远程ftp服务器进行测试

   

  这里是通过浏览器进行连接的。wireshark 1.12.4 从上面可以看到的信息 29-44这些表示了,浏览器一开始使用匿名进行登录,发现登录不上,所以请求用户名登录在81 82 84 85这4行中我们可以分析到,我是输入用户名user 密码user进行登录的,第106行表示用户名/密码错误。 如果是230 Login in 就表示成功登录了。如果我们捉到了这些信息,那么我们就可以进行登录了。这样就不安全了。既然ftp这么不安全为什么那么多地方用到ftp共享文件。这个就要说到ftp的作用了,ftp作用本来就是共享文件,所以安全性就不是很重要了。 至于加密方式以后再讲。

  (开发环境mignw 编译的时候要加入libws2_32.a 这个库, 编译命令 g++ ftpapi.cpp -c -o ftpapi.o -lws2_32)

  参考资料

  TanHao的 THFTPAPI.c 文件 http://www.tanhao.me

  文件下载 ftpapi.zip http://files.cnblogs.com/files/wunaozai/ftpapi20150512.zip

Socket网络编程--FTP客户端(1)(Windows)的更多相关文章

  1. Socket网络编程--FTP客户端(2)(Windows)

    上一篇FTP客户端讲到如果制作一个简单的FTP客户端,功能实现了,但是后面我们发现了问题,就是FTP是使用明文进行操作的.对于普通情况来说就无所谓了.但有时候要安全的一点的话,就应该使用FTP的安全版 ...

  2. Socket网络编程--FTP客户端

    Socket网络编程--FTP客户端(1)(Windows) 已经好久没有写过博客进行分享了.具体原因,在以后说. 这几天在了解FTP协议,准备任务是写一个FTP客户端程序.直接上干货了. 0.了解F ...

  3. Socket网络编程--FTP客户端(60篇socket博客,而且都比较简单、深入浅出)

    已经好久没有写过博客进行分享了.具体原因,在以后说. 这几天在了解FTP协议,准备任务是写一个FTP客户端程序.直接上干货了. 0.了解FTP作用 就是一个提供一个文件的共享协议. 1.了解FTP协议 ...

  4. 基于Socket网络编程

    版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/a2011480169/article/details/73602708 博客核心内容: 1.Sock ...

  5. windows下的socket网络编程

    windows下的socket网络编程 windows下的socket网络编程 clinet.c 客户端 server.c 服务器端 UDP通信的实现 代码如下 已经很久没有在windows下编程了, ...

  6. windows下的socket网络编程(入门级)

    windows下的socket网络编程 clinet.c 客户端 server.c 服务器端 UDP通信的实现 代码如下 已经很久没有在windows下编程了,这次因为需要做一个跨平台的网络程序,就先 ...

  7. 循序渐进Socket网络编程(多客户端、信息共享、文件传输)

    循序渐进Socket网络编程(多客户端.信息共享.文件传输) 前言:在最近一个即将结束的项目中使用到了Socket编程,用于调用另一系统进行处理并返回数据.故把Socket的基础知识总结梳理一遍. 1 ...

  8. windows socket 网络编程

    样例代码就在我的博客中,包含六个UDP和TCP发送接受的cpp文件,一个基于MFC的局域网聊天小工具project,和此小工具的全部执行时库.资源和执行程序.代码的压缩包位置是http://www.b ...

  9. Python Socket 网络编程 (客户端的编程)

    Socket 是进程间通信的一种方式,它与其他进程间通信的一个主要不同是:它能实现不同主机间的进程间通信,我们网络上各种各样的服务大多都是基于 Socket 来完成通信的,例如我们每天浏览网页.QQ ...

随机推荐

  1. hdu 4635 Strongly connected 强连通缩点

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4635 题意:给你一个n个点m条边的图,问在图不是强连通图的情况下,最多可以向图中添多少条边,若图为原来 ...

  2. selenium如何跳转到iframe

    处理iframe,selenium提供了3中方法: 1.html的frame有id,传入id 2.html的frame有name,传入name 3.先找到iframe的元素,再传入该元素对象 跳出if ...

  3. 分析递归式 Solving Recurrences------GeeksforGeeks 翻译

    在上一章中我们讨论了如何分析循环语句.在现实中,有很多算法是递归的,当我们分析这些算法的时候我们要找到他们的的递归关系.例如归并排序,为了排序一个数组,我们把它平均分为两份然后再重复平分的步骤.最后我 ...

  4. SSO - 我们为何需要单点登录系统

    SSO,Single Sign On,也就是单点登录,保证一个账户在多个系统上实现单一用户的登录 现在随着网站的壮大,很多服务会进行拆分,会做SOA服务,会使用dubbo做微服务,或者简单的小型分布式 ...

  5. [cb]Unity 项目架构

    一.技能机制 二.游戏工程 三.客户端架构

  6. SpringMVC系列之基本配置

    一.概述 Spring Web MVC是一种基于Java的实现了Web MVC设计模式的请求驱动类型的轻量级Web框架,即使用了MVC架构模式的思想,将web层进行职责解耦,基于请求驱动指的就是使用请 ...

  7. Volley(六 )—— 从源码带看Volley的缓存机制

    磁盘缓存DiskBasedCache 如果你还不知道volley有磁盘缓存的话,请看一下我的另一篇博客请注意,Volley已默认使用磁盘缓存 DiskBasedCache内部结构 它由两部分组成,一部 ...

  8. mysql视图的创建

    视图内容的变化跟它所依赖的表的变化是同步的也是一致的. create or replace view viewname as select a.id.,a.name,a.sex,b.aid,b.sco ...

  9. WPF Extended WPF Toolkit

    1.VS 2013 通过NUGet获取Extended WPF Toolkit 我自己的项目已安装 2.在自己页面引用Extended WPF Toolkit xmlns:xctk="htt ...

  10. 05Spring_Bean属性的集合类型的注入