C语言文件传输客户端

来源:互联网 发布:北京立方米网络 编辑:程序博客网 时间:2024/05/11 19:37

2.重要套接口函数

Socket函数:

#include<sys/socket.h>

int socket(int family,int type,int protocol);

返回非负描述字则成功,-1出错。

family指明协议族(IPv4IPv6Unix),type表示套接口的类型,protocol一般设置为0

 

Connect函数:

#include<sys/socket.h>

int connect(int sockfd,const struct sockaddr * servaddr, socklen_t addrlen);

返回0成功,-1出错。

Sockfd是由socket函数返回的套接口描述字,第二、第三个参数分别是一个指向套接口地址结构的指针和该结构的大小。地址结构必须含有服务器的IP地址和端口号。

 

Bind函数

#include<sys/socket.h>

int bind(int sockfd,const struct sockaddr * myaddr, socklen_t addrlen);

返回0成功,-1出错。

第二个参数是一个指向特定协议的地址结构的指针,第三个参数是该地址结构的长度。这个函数给套接口分配一个协议地址,协议地址的含义取决于协议本身。

 

Listen函数:

#include<sys/socket.h>

int listen(int sockfd,int bavklog);

返回0成功,-1出错。

第二个参数规定了内核为此套接口排队的最大连接个数。函数listen只被服务器调用,将未连接的套接口转换成被动套接口,指示内核应接受指向此套接口的连接请求。调用此函数可使套接口从CLOSED状态转换到LISTEN状态。

 

Accept函数:

#include<sys/socket.h>

int accept(int sockfd,const struct sockaddr * cliaddr, socklen_t addrlen);

返回非负描述字成功,-1出错。

此函数由服务器调用,从已完成连接队列头返回下一个已完成连接。若已完成连接队列为空,则进程睡眠。参数cliaddraddrlen用来返回连接对方进程(客户)的协议地址。

 

Close函数:

#include<unistd.h>

int close(int sockfd);

套接口的close缺省功能是将套接口做上“已关闭”标记,并立即返回到进程。这个套接口描述字不能再为进程所用。

 

Shutdown函数:

#include<sys/socket.h>

int shutdown(int s,int how);

成功返回0,否则返回-1

该函数调用将导致socket描述符s所指的全双工socket连接被部分或全部关闭。

 

Getsockoptsetsockopt函数;

#include<sys/socket.h>

int getsockopt(int sockfd,int level,int optname,void *optval,socklen_t *optlen);

int setsockopt(int sockfd,int level,int optname,const void *optval,socklen_t *optlen);

sockfd必须指向一个打开的套接字,level指定系统中解释选项的代码:普通套接口代码或特定于协议的代码;optval是一个指向变量的指针。

 

Recvsend函数:

#include<sys/socket.h>

ssize_t rect(int sockfd,void * buff,size_t nbytes,int flags);

ssize_t send(int sockfd,const void * buff,size_t nbytes,int flags);

成功则返回读入或写出的字节数,出错返回-1

这两个函数和标准的readwrite函数很类似,只是多了一个附加的参数flags

 

3.文件I/O与高级文件操作函数

open函数:

#include<sys/types.h>

#include<sys/stat.h>

#include<fcnt1.h>

int open(const char *pathname,int flags,…mode_t mode);

打开(或创建)文件失败返回-1

第一个参数pathname是要打开(或创建)的文件名或含路径的文件名。第二个参数是标志打开的方式,这个参数用来说明这个系统调用的多个选择项。

 

creat函数:

#include<sys/types.h>

#include<sys/stat.h>

#include<fcnt1.h>

int creat(const char *pathname, mode_t mode);

创建文件失败返回-1

参数含义与open函数相同。

 

read函数:

#include<unist.h>

size_t read(int filedes,void *buff,size_t nbytes);

调用成功返回读取的字节数,返回0表示文件指针在文件尾。错误返回-1

该函数从文件描述符fd所指的文件中读取nbytes字节到buff所指向的内存缓冲中。

 

write函数:

#include<unist.h>

size_t write(int filedes,void *buff,size_t nbytes);

调用成功返回写入的字节数,返回0表示没有数据要写。错误返回-1

该函数用来将内存中的数据写入已打开的文件中。

 

opendir/readdir/closedir函数:

#include<sys/types.h>

#include<dirent.h>

DIR * opendir(const char *name);

struct dirent *readdir(DIR *dir);

int closedir(DIR *dir);

opendir函数用来打开一个目录项,readdir读取目录项中的内容,closedir关闭一个已经打开的目录项。

 

chmod函数:

#include<sys/types.h>

#include<sys/stat.h>

int chmod(const char *path, mode_t mode);

调用成功返回0,错误返回-1

该函数用于修改任何类型的一个现存文件的存取许可权。

 

mkdir/rmdir函数:

#include<sys/types.h>

#include<sys/stat.h>

#include<fcnt1.h>

#include<unistd.h>

int mkdir(const char *pathname, mode_t mode);

int mkdir(const char *pathname);

调用成功返回0,错误返回-1

mkdir函数用来创建一个新的目录,rmdir删除一个已有的空目录。

 

unlink函数:

#include<unistd.h>

int unlink(const char *pathname);

调用成功返回0,错误返回-1

该函数用于删除一个目录项或文件。

 

chdir函数:

#include<unistd.h>

int chdir(const char *path);

调用成功返回0,错误返回-1

该函数用于改变当前工作目录。

 

 

二、客户端功能实现与关键函数

1.连接到服务器

函数get_user()get_pass()得到用户输入的用户名和密码。ftp_login()函数用输入字符与缺省用户名密码、匿名用户密码相比较,如果一致则登陆成功,否则失败。

void get_user()//得到输入用户名

{

       char read_buf[64];

       printf("User(Press  for anonymous): ");

       fgets(read_buf, sizeof(read_buf), stdin);

       if(read_buf[0]=='/n')

              strncpy(user, "anonymous", 9);

       else

              strncpy(user, read_buf, strlen(read_buf)-1);

}

 

void get_pass()//得到输入密码

{

       char read_buf[64];

       printf("Password(Press  for anonymous): ");

       echo_off();//隐藏密码

       fgets(read_buf, sizeof(read_buf), stdin);

       if(read_buf[0]=='/n')

              strncpy(passwd, "anonymous", 9);

       else

              strncpy(passwd, read_buf, strlen(read_buf)-1);

       echo_on();//取消隐藏

       printf("/n");

}

int ftp_login()//登陆函数

{

       int err;

       get_user();

       if(ftp_send_cmd("USER ", user, sock_control) < 0)

              cmd_err_exit("Can not send message",1);;

       err = ftp_get_reply(sock_control);//得到服务器返回

       if(err == 331)

       {

              get_pass();

              if(ftp_send_cmd("PASS ", passwd, sock_control) <= 0)

                     cmd_err_exit("Can not send message",1);

              else

                     err = ftp_get_reply(sock_control);

              if(err == 230)//缺省用户

              {

                     return 1;

              }

else if(err == 531)//匿名用户

{

       return 2

}

else

{

              printf("Password error!/n");

                     return 0;

}

       }

       else

       {

              printf("User error!/n");

              return 0;

       }

}

 

函数int xconnect(struct sockaddr_in *s_addr, int type)连接到服务器。

int xconnect(struct sockaddr_in *s_addr, int type)

{

       struct timeval outtime;

       int set;

       int s = socket(AF_INET, SOCK_STREAM, 0);

       if(s < 0)

              cmd_err_exit("creat socket error!", 249);

 

       set = setsockopt(s, SOL_SOCKET,SO_RCVTIMEO, &outtime,sizeof(outtime));

       if(set !=0)

       {

              printf("set socket %s errno:%d/n",strerror(errno),errno);

              cmd_err_exit("set socket", 1);

       }

 

       //connect to the server

       if (connect(s,(struct sockaddr *)s_addr,sizeof(struct sockaddr_in)) < 0)

       {

              printf("Can't connect to server %s, port %d/n",/

                     inet_ntoa(s_addr->sin_addr),ntohs(ftp_server.sin_port));

              exit(252);

       }

       return s;

}

fgets(read_buf, sizeof(read_buf), stdin);

得到用户名和密码的关键函数。读入数据。

 

int s = socket(AF_INET, SOCK_STREAM, 0);

if(s < 0)

       cmd_err_exit("creat socket error!", 249);

创建套接字,如创建成功,socket函数返回非负值。

       //connect to the server

       if (connect(s,(struct sockaddr *)s_addr,sizeof(struct sockaddr_in)) < 0)

       {

              printf("Can't connect to server %s, port %d/n",/

                     inet_ntoa(s_addr->sin_addr),ntohs(ftp_server.sin_port));

              exit(252);

       }

连接到服务器,如果连接成功,connect函数返回0,如果不成功,返回-1

 

int ftp_send_cmd(const char *s1, const char *s2, int sock_fd)

向服务器发送客户端的命令的函数。

int ftp_send_cmd(const char *s1, const char *s2, int sock_fd)

{

       char send_buf[256];

       int send_err, len;

       if(s1)

       {

              strcpy(send_buf,s1);

              if(s2)

              {    

                     strcat(send_buf, s2);

                     strcat(send_buf,"/r/n");

                     len = strlen(send_buf);

                     send_err = send(sock_fd, send_buf, len, 0);

              }

              else

              {

                     strcat(send_buf,"/r/n");

                     len = strlen(send_buf);

                     send_err = send(sock_fd, send_buf, len, 0);

              }

           }

       if(send_err < 0)

              printf("send() error!/n");

       return send_err;

}

 

接收服务器返回信息函数

//get the server's reply message from sock_fd

int ftp_get_reply(int sock_fd)

{

       static int reply_code = 0,count=0;

       char rcv_buf[512];

       count=read(sock_fd, rcv_buf, 510);

       if(count > 0)

              reply_code = atoi(rcv_buf);

       else

              return 0;

       while(1)

       {

              if(count <= 0)

                     break;

              rcv_buf[count]='/0';

              printf("%s",rcv_buf);

              count=read(sock_fd, rcv_buf, 510);

       }

       return reply_code;

}

send_err = send(sock_fd, send_buf, len, 0);

send函数发送成功返回字节数大于0,小于0则出错。

 

int xconnect_ftpdata()

连接服务器数据流函数。

get_sock = socket(AF_INET, SOCK_STREAM, 0);

set = setsockopt(get_sock, SOL_SOCKET,SO_RCVTIMEO, /

                            &outtime,sizeof(outtime));

set = setsockopt(get_sock, SOL_SOCKET,SO_REUSEADDR, /

                            &opt,sizeof(opt));

新建套接字传输数据流。

set = bind(get_sock, (struct sockaddr *)&local_host, /

                                   sizeof(local_host));

if(set != 0 && errno == 11)

{

       client_port = rand_local_port();

       continue;

}

set = listen(get_sock, 1);

bindlisten函数开启数据流传输。

 

进行客户端操作关键函数

void open_ftpsrv()//客户端操作函数

{

       char usr_cmd[1024];

       int cmd_flag;

       while(1)

       {

              printf("ftp_cli>");

              fgets(usr_cmd,510,stdin);

              fflush(stdin);

              if(usr_cmd[0] == '/n')

                     continue;

              usr_cmd[strlen(usr_cmd)-1] = '/0';

              cmd_flag = ftp_usr_cmd(usr_cmd);

              if(cmd_flag == 15)

              {

                     char *cmd = strchr(usr_cmd,' ');

                     char dress_ftp[1024];

                     if(cmd == NULL)

                     {

                            printf("command error!/n");

                            show_help();

                            return;

                     }

                     else

                     {

                            while(*cmd == ' ')

                                   cmd++;

                     }

                     if(cmd == NULL||cmd == '/0')

                     {

                            printf("command error!/n");

                            return;

                     }

                     else

                     {

                            char * dr = "127.0.0.1";

                            strncpy(dress_ftp,cmd,strlen(cmd));

                            dress_ftp[strlen(cmd)] = '/0';

                            printf("%s",dress_ftp);

                            if(dress_ftp == "127.0.0.1")

                            {

                                   printf("Connect Seccessed!/n");

                                   start_ftp_cmd(dr,DEFAULT_FTP_PORT);

//open成功则调用该函数,该函数与open_ftpsrv()很相似。

                            }

                            else

                            {

                                   printf("Inviable Server Dress!/n");

                            }    

                     }

              }

              else

//如果open不成功,则只能进行客户端上的操作,不能进行有关服务器操作

              {

                     switch(cmd_flag)

                     {

                            case 11:

                                   local_list();

                                   memset(usr_cmd,'/0',sizeof(usr_cmd));

                                   break;

                            case 12:

                                   local_pwd();

                                   memset(usr_cmd,'/0',sizeof(usr_cmd));

                                   break;

                            case 13:

                                   local_cd(usr_cmd);

                                   memset(usr_cmd,'/0',sizeof(usr_cmd));

                                   break;

                            case 6://quit

                                   printf("BYE TO WEILIQI FTP!/n");

                                   exit(0);

                                   break;

                            default:

                                   printf("command error!/n");

                                   show_help();

                                   memset(usr_cmd,'/0',sizeof(usr_cmd));

                                   break;

                     }

              }

       }           

             

}

2.目录文件操作

void ftp_list()

显示服务器当前目录下文件的函数。

 

int list_sock_data = xconnect_ftpdata();

创建一个新套接字,表示是否连接上服务器的数据。

ftp_send_cmd("LIST", NULL, sock_control);

ftp_get_reply(sock_control);

向服务器发送命令,得到服务器的响应答复。

new_sock = accept(list_sock_data, (struct sockaddr *)&local_host, /

                            (socklen_t *)&set);

从服务器接收数据(文件信息)。

 

void ftp_cmd_filename(char * usr_cmd, char * src_file, char * dst_file)

此函数读取客户端命令后的文件名字。在很多命令中,如getput后要加入上传或下载的文件名字,这个函数解析文件名字信息。

 

void local_pwd()

显示客户端目录函数。

//print local current directory

void local_pwd()

{

       char curr_dir[512];

       int size = sizeof(curr_dir);

       if(getcwd(curr_dir, size) == NULL)

              printf("getcwd failed/n");

       else

              printf("Current local directory: %s/n", curr_dir);

}

getcwd(curr_dir, size)得到客户端目录。

 

void ftp_cd(char * usr_cmd)

转换服务器目录函数。

void ftp_cd(char * usr_cmd)

{

       char *cmd = strchr(usr_cmd, ' ');

       char path[1024];

       if(cmd == NULL)

       {

              printf("command error!/n");

              return;

       }

       else

       {

              while(*cmd == ' ')

                     cmd ++;

       }

       if(cmd == NULL || cmd == '/0')

       {

              printf("command error!/n");

              return;

       }

       else

       {

              strncpy(path, cmd, strlen(cmd));

              path[strlen(cmd)]='/0';

              ftp_send_cmd("CWD ", path, sock_control);

              ftp_get_reply(sock_control);

       }

}

 

ftp_send_cmd("CWD ", path, sock_control);

ftp_get_reply(sock_control);

发送转换目录命令给服务器,服务器完成该功能。

 

创建目录函数void mkdir_srv(char * usr_cmd) 和删除目录函数void rmdir_srv(char * usr_cmd)void ftp_cd(char * usr_cmd)函数相似,在此不做解释。

 

 

函数void local_list()列出客户端文件列表。

void local_list()

{

       DIR * dp;

       struct dirent *dirp;

       if((dp = opendir("./")) == NULL)

       {

              printf("opendir() error!/n");

              return;

       }

       printf("Local file list:/n");

       while((dirp = readdir(dp)) != NULL)

       {

              if(strcmp(dirp->d_name, ".") == 0 || strcmp(dirp->d_name, "..") == 0)

                     continue;

              printf("%s/n", dirp->d_name);

       }

}

 

转换客户端目录函数

void local_cd(char * usr_cmd)

{

       char *cmd = strchr(usr_cmd, ' ');

       char path[1024];

       if(cmd == NULL)

       {

              printf("command error!/n");

              return;

       }

       else

       {

              while(*cmd == ' ')

                     cmd ++;

       }

       if(cmd == NULL || cmd == '/0')

       {

              printf("command error!/n");

              return;

       }

       else

       {

              strncpy(path, cmd, strlen(cmd));

              path[strlen(cmd)]='/0';

              if(chdir(path) < 0)  //转换目录

                     printf("Local: chdir to %s error!/n", path);

              else

                     printf("Local: chdir to %s/n", path);

       }

}