Fastdfs is a lightweight, distributed file system, consisting primarily of tracker server, storage server, and client, which mainly involves two points:
1 Client upload file process and protocol analysis
2 implementation of a simple file upload function
One: The basic process of file upload
Fastdfs upload a file, mainly involves the following several steps:
1 Upload the connection request, the client will send the request of uploading file to tracker server
2 Tracker after receiving the request, return the IP and port of storage server
3 Client connection storage, and upload file
4 after the completion of the file upload, storage return path information
The following detailed analysis of the file upload process of the protocol and various operations
Fastdfs protocol head:
typedef struct
{
char pkg_len[fdfs_proto_pkg_len_size]; Body length, not including header (8 bytes)
char cmd; Command code tracker_proto_cmd_service_query_store_without_group_one
char status;//status code for Response
} Trackerheader;
The head of the FASTDFS protocol is composed of a 10-byte structure,
Send: Send the data, first send Trackerheader to the server, then send the specific data
Acceptance: Accept the data, first accept the sizeof (Trackerheader) size of the message head, and then accept the Pkg_len length of the report style
Status: Set to 0 when sent
CMD: command
Pkg_len: A int64_t integral type that removes the length of the message Trackerheader length
Two: The client sends the storage address request to the tracker server
#define Tracker_proto_cmd_service_query_store_without_group_one
Protocol head//Pkg_len | cmd | Status//8 bytes | 1 bytes |
1 bytes//request to TRACKER Server storage server cmd #define TRACKER_PROTO_CMD_SERVICE_QUERY_STORE_WITHOUT_GROUP_ONE 101
Trackerheader header;//Protocol Head memset (&header, 0, sizeof (trackerheader));
Header.cmd = Tracker_proto_cmd_service_query_store_without_group_one; Request Storage,tcpsenddata return non 0 to tracker server to send success if (Tcpsenddata sockfd, &header, sizeof (Trackerheader), &A
Mp;count)!= 0) {fprintf (stderr, "Tcpsenddata Error:%s\n", Strerror (errno));
return 1;
else//request sent successfully, waiting for tracker reply {///Receive Head, head is a trackerheader type, 10 bytes Trackerheader resp; if ((Ret_code = Tcprecvdata (sockfd, &resp, sizeof (Trackerheader), &count))!= 0) {fprintf
(stderr, "Tcprecvdata Error:%s\n", Strerror (Ret_code));
return 1;
//start receiving newspaper stylistic//int64_t Read_int64 (const char *buff) {//unsigned char *p;
p = (unsigned char *) buff; Return (((int64_t) (*p)) << 56) | \//((int64_t) (* (p+1)) << 48) | \//((int64_t) (* (p+2)) << 40) | \//((int64_t) (* (p+3)) << 32) | \//((int64_t) (* (p+4)) << 24) | \//((int64_t) (* (p+5)) << 16) | \//((int64_t) (* (p+6)) << 8) |
\//((int64_t) (* (p+7));
int size = Read_int64 (Resp.pkg_len);//Get the body length char *buf = (char*) calloc (size + 1, sizeof (char)); if ((Ret_code = Tcprecvdata (SOCKFD, buf, size, &count)!= 0)) {fprintf (stderr, "Tcprecvda")
TA error:%s\n ", Strerror (Ret_code));
return 1; }//Newspaper style//group_name |ip |port |storage_index/bytes |16 bytes |8 b
Ytes | #define Tracker_query_storaGe_store_body_len-if (count!= tracker_query_storage_store_body_len) {fprintf (stderr, "Inva
Lid message ");
return 1; }//group name//#define Fdfs_group_name_max_len Char Group_name[fdfs_group_name_max_len +
1] = {0};
memcpy (Group_name, buf, Fdfs_group_name_max_len);
Group_name[fdfs_group_name_max_len] = ' the ';
Ip:port//#define ip_address_size//port:8 bytes Char ip[ip_address_size + 1] = {0};
memcpy (IP, buf + fdfs_group_name_max_len, ip_address_size-1);
Char Szport[8] = {0};
memcpy (Szport, buf + Fdfs_group_name_max_len + ip_address_size-1, 8);
Ip[ip_address_size] = ' the ';
int port = Read_int64 (Szport);
Storage index;
Char *storage_index = buf + Fdfs_group_name_max_len + ip_address_size-1 + fdfs_proto_pkg_len_size;
three: After the completion of the above steps, get storage IP and port, you can upload files
In the official client, the file operation has upload,download, Append,delete and so on, here only involves the upload
In the upload file, the official gives three ways
1 through the buffer upload, the file will be read into memory, and then send
2 using Sendfile,sendfile is a library function provided by Linux
3 by means of a callback function
This is mainly concerned with the first kind, by the way of buffer upload
File Upload protocol:
File Upload protocol head
bytes | 1 bytes | 8 bytes | 6 bytes |
Trackerheader | storage_index | file length | filename or all 0) |
Storage_index is the result//file name returned by the client applying to tracker server storage index If it is
not empty, take the top 6 digits, or you can set it all to 0
//upload complete Storage Reply Client protocol
bytes | bytes | Trackerheader.pkg_len-16bytes
trackerheader | groupname | remote file name
void UploadFile (int sockfd, const char *filepath, char *storage_index) {char out_buf[512];
Trackerheader *pheader;
char *p = out_buf;
char *buf = NULL; Trackerheader Bytes//File Upload Protocol head//10 bytes | 1 bytes | 8 bytes |
6 bytes | Trackerheader | Storage_index | File Length |
FileName or all 0) |
Pheader = (trackerheader*) out_buf;
p + + sizeof (Trackerheader);
Storage index 1 bytes *p++ = *storage_index;
FileSize 8bytes long int filesize = 0;
int ret = 0; Reads the file to BUF and returns the file length FileSize if ((ret = Getfilebuf (&buf, &filesize, filepath)!= 0)) {fprintf (stde
RR, "Getfilebuf failed:%s\n", strerror (ret));
Return
}//void Write_int64 (int64_t N, char *buff)//{//unsigned char *p;
p = (unsigned char *) buff;
*p++ = (n >> a) & 0xFF;
*p++ = (n >> a) & 0xFF;
*p++ = (n >>) & 0xFF; *p++ = (n >>) & 0xFF;
*p++ = (n >>) & 0xFF;
*p++ = (n >>) & 0xFF;
*p++ = (n >> 8) & 0xFF;
*p++ = n & 0xFF;
} write_int64 (FileSize, p);
#define FDFS_PROTO_PKG_LEN_SIZE 8 p + + fdfs_proto_pkg_len_size;
Ext_name//#define Fdfs_file_ext_name_max_len 6 memset (p, 0, Fdfs_file_ext_name_max_len);
p + + Fdfs_file_ext_name_max_len;
Set Trackerheader Write_int64 (P-out_buf + filesize-sizeof (trackerheader), Pheader->pkg_len);
#define Storage_proto_cmd_upload_file pheader->cmd = storage_proto_cmd_upload_file;
Pheader->status = 0;
Send message head int count;
int ret_code = 0; if ((Ret_code = Tcpsenddata (SOCKFD, Out_buf, P-out_buf, &count)!= 0)) {fprintf (stderr, "Tcpsenddata FAI
LED:%s\n ", Strerror (errno));
Return //Send a report style, specific file data if ((Ret_code = Tcpsenddata (SOCKFD, buf, FileSize, &count))!= 0) {fprintf (stderr, "Tcpsenddata body failed:%s\n", Strerror (errno));
Return //Receive Storage server reply//upload complete Storage reply client protocol//10 bytes | bytes | Trackerheader.pkg_len-16bytes//trackerheader | GroupName |
Remote file name Trackerheader resp; if ((Ret_code = Tcprecvdata (sockfd, &resp, sizeof (Trackerheader), 1000, &count))!= 0) {fprintf (stderr, "t
Cprecvdata failed:%s\n ", Strerror (Ret_code));
Return
} if (Count!= sizeof (Trackerheader)) {fprintf (stderr, "Invalid header");
Return
} int64_t Bodylen = Read_int64 (Resp.pkg_len);
Receive newspaper stylistic char *in_buf = (char*) calloc (Bodylen + 1, sizeof (char)); if ((Ret_code = Tcprecvdata (SOCKFD, In_buf, Bodylen, &count))!= 0) {fprintf (stderr, "read Body Faile
D:%s\n ", Strerror (Ret_code));
Return //groupname//#define Fdfs_group_name_max_len Char Group_name[fdfs_group_name_mAx_len + 1];
memcpy (Group_name, In_buf, Fdfs_group_name_max_len);
Group_name[fdfs_group_name_max_len] = ' the ';
Remote filename char Remote_filename[bodylen-fdfs_group_name_max_len + 1];
memcpy (remote_filename, In_buf + fdfs_group_name_max_len, Bodylen-fdfs_group_name_max_len + 1);
cout << "groupname:" << group_name << Endl;
cout << "Remote_filename:" << remote_filename << Endl;
Char httpaddr[128] = {0};
sprintf (httpaddr, "http://106.75.129.177:8080/%s/%s", Group_name, Remote_filename); cout << "httpaddr:" << httpaddr << endl;//http Address}
The following is enclosed with complete code, UBUNTU14 bit, compiler g++, test passed
#include <iostream> #include <sys/socket.h> #include <arpa/inet.h> #include <errno.h> #include
<unistd.h> #include <fcntl.h> #include <stdlib.h> #include <stdio.h> #include <string.h>
using namespace Std; #define FDFS_GROUP_NAME_MAX_LEN #define FDFS_PROTO_PKG_LEN_SIZE 8 #define Ip_address_size//cmd #def INE Tracker_proto_cmd_service_query_store_without_group_one #define Storage_proto_cmd_upload_file #defin E Tracker_query_storage_store_body_len (Fdfs_group_name_max_len + ip_address_size-1 + FDFS_PROTO_PKG_LEN_SIZE +
1) #define Fdfs_file_ext_name_max_len 6 typedef struct {char pkg_len[fdfs_proto_pkg_len_size];
char cmd;
char status;
}trackerheader;
Set SOCKETFD nonblocking int setnonblocking (int sockfd);
int tcprecvdata (int sockfd, void *data, const int size,\ const int Timeout_ms, int *count); int tcpsenddata (int sockfd, void *data, const int size,\ const INT timeOut_ms, int *count);
int64_t Read_int64 (const char* BUF);
void Write_int64 (int64_t N, char* buf);
void UploadFile (int sockfd, const char *filepath, char *storage_index);
int Getfilebuf (char **buf, long int *filesize, const char* filepath);
Apply storage address from Tracker server int main () {const char *IP = "127.0.0.1";
uint16_t port = 22122;
int ret_code = 0;
int sockfd =-1;
int count = 0; Connect Tracker Server if (SOCKFD = socket (pf_inet, sock_stream, 0)) < 0) {fprintf (stderr, "socket
Errnor:%s\n ", Strerror (errno));
return 1; } if ((Ret_code = setnonblocking (sockfd))!= 0) {fprintf (stderr, "setnonblocking Error:%s\n", Strerror (R
Et_code));
return 1;
} struct sockaddr_in addr;
ADDR.SIN_ADDR.S_ADDR = inet_addr (IP);
Addr.sin_port = htons (port);
addr.sin_family = af_inet;
socklen_t len = sizeof (struct sockaddr); if (Connect (SOCKFD, (struct sockaddr*) &addr, Len) &lT
0) {fprintf (stderr, "Connect error:%s\n", Strerror (errno));
return 1;
} Trackerheader header;
memset (&header, 0, sizeof (trackerheader));
Header.cmd = Tracker_proto_cmd_service_query_store_without_group_one; if (Tcpsenddata (SOCKFD, &header, sizeof (Trackerheader), &count)!= 0) {fprintf (stderr, "Tcpsenddat")
A error:%s\n ", Strerror (errno));
return 1;
else {//RECV header Trackerheader resp; if ((Ret_code = Tcprecvdata (sockfd, &resp, sizeof (Trackerheader), &count))!= 0) {fprintf
(stderr, "Tcprecvdata Error:%s\n", Strerror (Ret_code));
return 1;
} cout << "recv header:" << count << Endl;
Read body;
int size = Read_int64 (Resp.pkg_len);
Char *buf = (char*) calloc (size + 1, sizeof (char));
if ((Ret_code = Tcprecvdata (SOCKFD, buf, size, &count)!= 0)) {fprintf (stderr, "Tcprecvdata Error:%s\n", Strerror (Ret_code));
return 1; }//body//group_name |ip |port |storage_index//16bytes |16bytes |8bytes
|
cout << "read body:" << count << Endl;
if (count!= tracker_query_storage_store_body_len) {fprintf (stderr, "Invalid message");
return 1;
}//group Name char Group_name[fdfs_group_name_max_len + 1] = {0};
memcpy (Group_name, buf, Fdfs_group_name_max_len);
Group_name[fdfs_group_name_max_len] = ' the ';
cout << "group name:" << group_name << Endl;
Ip:port Char ip[ip_address_size + 1] = {0};
memcpy (IP, buf + fdfs_group_name_max_len, ip_address_size-1);
Char Szport[8] = {0};
memcpy (Szport, buf + Fdfs_group_name_max_len + ip_address_size-1, 8); Ip[ip_address_size] = '';
int port = Read_int64 (Szport);
cout << "Address: << IP <<": << Port << Endl;
Storage index;
Char *storage_index = buf + Fdfs_group_name_max_len + ip_address_size-1 + fdfs_proto_pkg_len_size;
cout << "Storage_index:" << storage_index << Endl;
Free (BUF);
Connect storage server sockaddr_in st_addr;
ST_ADDR.SIN_ADDR.S_ADDR = inet_addr (IP);
st_addr.sin_family = af_inet;
St_addr.sin_port = htons (port);
int STORAGE_FD = socket (af_inet, sock_stream, 0);
if (STORAGE_FD < 0) {fprintf (stderr, "Socket failed:%s\n", Strerror (errno));
return 1;
} socklen_t len2 = sizeof (sockaddr_in); if (Connect (storage_fd, (struct sockaddr*) &st_addr, Len2) < 0) {fprintf (stderr, "Connect failed:%s\n",
Strerror (errno));
return 1; } uploadfile (STORAGE_FD, "1.jpg", Storage_index);
return 0;
int Getfilebuf (char **buf, long int *filesize, const char *filepath) {int ret_code = 0;
FILE *FP = fopen (filepath, "rb+");
if (fp = = NULL) {ret_code = errno;
return ret_code;
}//get filesize;
Fseek (FP, 0, Seek_end);
*filesize = Ftell (FP);
Fseek (FP, 0, Seek_set);
cout << "Get filesize:" <<*filesize << Endl;
malloc buf *buf = (char*) calloc (*filesize + 1, sizeof (char));
if (*buf = = NULL) {ret_code = errno;
return ret_code;
int read_bytes = 0;
int left_bytes = *filesize;
char *p = *buf;
while (Left_bytes > 0) {read_bytes = Fread (p, sizeof (char), left_bytes, FP);
Left_bytes-= read_bytes;
p + + read_bytes;
return ret_code;
} void UploadFile (int sockfd, const char *filepath, char *storage_index) {char out_buf[512];
Trackerheader *pheader;
char *p = out_buf;char *buf = NULL;
Trackerheader bytes Pheader = (trackerheader*) out_buf;
p + + sizeof (Trackerheader);
Storage index 1 bytes *p++ = *storage_index;
FileSize 8bytes long int filesize = 0;
int ret = 0; if (ret = Getfilebuf (&buf, &filesize, filepath)!= 0)) {fprintf (stderr, "Getfilebuf failed:%s\n", St
Rerror (ret));
Return
printf ("FileSize:%ld\n", filesize);
Write_int64 (FileSize, p);
p + + fdfs_proto_pkg_len_size;