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

  这几天在了解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. Linux Crash/Hang on Bay Trail/J1900/N2940

    近几年的linux kernel, 尤其是4.1以后,在Bay Trail平台上会随机挂起和死机,亲测j1900,死机非常频繁,而且死机前毫无征兆,直接就挂起了,console也没有相应. 这个问题在 ...

  2. 在 ServiceModel 客户端配置部分中,找不到引用协定“WebServiceTest.WebServiceSoap”的默认终结点元素。这可能是因为未找到应用程序的配置文件,或者是因为客户端元素

    原文  http://blog.csdn.net/bugdemo/article/details/9083497 主题 技术 在引用WebService后,程序运行到实例化WebService时报错, ...

  3. O(N)时间的排序

    题目:某公司有几万名员工,请完成一个时间复杂度为O(n)的算法对该公司员工的年龄作排序,可使用O(1)的辅助空间. 要注意分析题目,一般排序要么是O(n^2),要么是O(nlogn).但这里题目特别强 ...

  4. c#实现验证码功能

    一.验证码简介 验证码功能一般是用于防止批量注册的,不少网站为了防止用户利用机器人自动注册.登录.灌水,都采用了验证码技术.所谓验证码,就是将一串随机产生的数字或字母或符号或文字,生成一幅图片, 图片 ...

  5. 探索 OpenStack 之(12):cinder-api Service 处理 HTTP Request 的过程分析

    本文是上一篇 探索 OpenStack 之(11):cinder-api Service 启动过程分析 以及 WSGI / Paste deploy / Router 等介绍> 的后续篇. os ...

  6. [转]Try Cloud Messaging for Android

    本文转自:https://developers.google.com/cloud-messaging/android/start

  7. 【转载】PMC/PEC Boundary Conditions and Plane Wave Simulation

    原文链接 PMC/PEC Boundary Conditions and Plane Wave Simulation (FDTD) OptiFDTD now has options to use Pe ...

  8. 单元测试---googletest

    单元测试概述 测试并不只是测试工程师的责任,对于开发工程师,为了保证发布给测试环节的代码具有足够好的质量( Quality ),为所编写的功能代码编写适量的单元测试是十分必要的. 单元测试( Unit ...

  9. 注册其它地区Apple ID

    不同地区Apple Id需求 iPhone 最近换上了iPhone,想要下载其它国家地区的游戏,需要登录该国的Apple Id才能在itunes里下载. 下面记录一下我注册日本地区的Apple Id过 ...

  10. java 14 -7 Date

    Date:表示特定的瞬间,精确到毫秒. 了解了解就行. 已经过时,在 JDK 1.1 之前,类 Date 有两个其他的函数.它允许把日期解释为年.月.日.小时.分钟和秒值.它也允许格式化和解析日期字符 ...