目录
socket():创建一个网络通信端点原型:int socket(int domain, int type, int protocol);
atoi():将字符串转变成整型数据原型:int atoi(const char *nptr);
htons():将16位无符号数从主机字节序转换成网络字节序原型:uint16_t htons(uint16_t hostshort);
inet_aton():将IP地址从字符串类型转换成网络字节序原型:int inet_aton(const char *cp, struct in_addr *inp);
inet_ntoa():将IP地址从网络字节序转换成字符串类型原型:char *inet_ntoa(struct in_addr in);
bind():为套接字添加信息(协议族、IP地址、端口号)原型:int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
listen():监听客户端的连接原型:int listen(int sockfd, int backlog);
connect():客户端连接服务器原型:int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
fork():创建一个子进程原型:pid_t fork(void)
open():打开一个文件原型:int open(const char *pathname, int flags, mode_t mode);
read():从某个文件中读取数据,没读到数据时会阻塞等待原型:int read(int fd, void *buf, size_t count);
write():向某个文件写入数据原型:int write(int fd, const void *buf, size_t count);
lseek():移动文件的光标,通常用lseek(fd,0,SEEK_END)获取文件长度原型:int lseek(int fd, off_t offset, int whence);
close(),一般不用主动关闭文件,在进程终止时,内核自动关闭该进程打开的文件原型:int close(int fd)
strtok():字符串分割函数原型:char *strtok(char *str, const char *delim);
strcmp():字符串比较函数原型:int strcmp(const char *s1, const char *s2);
strstr():字符串包含函数原型:char *strstr(const char *s1, const char *s2);
strcat():字符串拼接函数原型:char *strcat(char *str1, const char *str2);
strcpy():字符串复制函数原型:char *strcpy(char *str1, const char *str2)
memset():将一块内存设定成指定的值原型:void *memset(void *s, int c, size_t n);
system():执行某个命令,命令执行后继续从调用点执行程序原型:int system(const char *command);
popen():执行某个命令,并将执行命令后得到的数据存放到一个文件流中原型:FILE *popen(const char *command, const char *type);
fread():从某个文件流中读取数据原型:int fread(void *ptr, size_t size, size_t nmemb,FILE *stream);
fflush():刷新缓冲区,将某个流未写的数据传送至内核原型:int fflush(FILE *stream);
chdir():修改当前的工作目录原型:int chdir(const char *path);
access():查看文件是否具有某个权限原型: int access(const char * pathname,int mode);
在 Linux 环境下使用文件、线程、网络编程等相关操作,实现 ls、lls、cd、lcd、put、get、pwd、lpwd 功能。 树莓派 3B 作为服务端、Ubuntu 作为客户端,允许 Ubuntu 上多个进程作客户端连接服务端。客户端使用 lls、 lcd、lpwd 命令查看客户端目录文件、切换工作目录、查看当前目录;使用 ls、cd、pwd 命令查看服务端目录文件、切换工作目录、查看当前目录;使用 put 加文件名将客户端文件上传至服务端,使用 get 加文件名从 服务端将文件下载至客户端,实现在同一局域网下树莓派 3B 和 Ubuntu 之间文件的



返回值:调用成功返回套接字描述符,调用失败返回-1
参数:
int domain:指明所使用的协议族,通常为 AF_INET,表示互联网协议族(TCP/IP 协议族)
int type:选择套接字的类型,在这里我们用SOCK_STREAM
int protocol:选择协议,通常为0, 表示type参数对应的默认协议
返回值:返回转换之后得到的int型数据
参数:
返回值:转换之后的TCP/IP网络字节序
参数:
返回值:调用成功返回非0,调用失败返回0
参数:
返回值:指向字符串类型IP地址的字符串指针
参数:
返回值:调用成功返回0,调用失败返回-1
参数:
返回值:调用成功返回0,调用失败返回-1
参数:
返回值:调用成功返回0,调用失败返回-1
参数:
返回值:调用成功返回套接字描述符,调用失败返回-1
参数:
返回值:调用成功返回两次,0或非负整数,调用失败返回-1
返回值:调用成功返回一个文件描述符,调用失败返回-1
参数:
返回值:读入成功时,返回读取的字节数(如果读文件开始前光标到达文件尾端则返回0)读入失败时,返回-1
参数:
返回值:写入成功时,返回写入的字节数,写入数据为空返回0,写入失败返回-1
参数:
返回值:调用成功返回光标偏移字节,调用失败返回-1
参数:
返回值:调用成功返回0,调用失败时返回-1
参数:
返回值:
参数:
返回值:如果两个字符串相等返回0,两个字符串不相等返回其他值
参数:
返回值:如果字符串s1包含字符串s2,返回包含字符及后面字符,如果字符串s1不包含字符串s2则返回NULL
参数:
返回值:返回指向字符串2拼接到字符串1的字符串地址的指针
参数:
返回值:返回指向字符串2复制到字符串1尾端的字符串地址的指针
参数:
返回值:返回一个指向内存s的指针
参数:
返回值:
参数:
返回值:调用成功返回文件流,调用失败返回NULL
参数:
返回值:读入成功时,返回读取的字节数,读入失败时,返回-1
参数:
返回值:调用成功返回0,调用失败返回EOF
参数:
返回值:调用成功返回0,调用失败返回-1
参数:
返回值:如果文件具有某种权限返回0,不具有某种权限返回-1
参数:
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
-
- #define LS 1
- #define CD 2
- #define PWD 3
- #define PUT 5
- #define GET 15
-
- struct Msg
- {
- int type;
- char cmd[50];
- char data[5120];
- };
-
- int cmd_distinguish(char *cmd)
- {
- int ret;
- cmd = strtok(cmd,"\n"); //由于客户端获取用户输入时,会使用enter键,因此传输到服务器的命令都带有换行符,需要进行命令分割
- if(!strcmp("ls",cmd)){
- ret = LS;
- }else if(strstr(cmd,"cd") != NULL){
- ret = CD;
- }else if(strstr(cmd,"get") != NULL){
- ret = GET;
- }else if(strstr(cmd,"put") != NULL){
- ret = PUT;
- }else if(!strcmp("pwd",cmd)){
- ret = PWD;
- }else{
- ret = 0;
- }
- return ret;
- }
-
- //将带有文件名、路径名的命令进行处理分割
- //如命令“get 1.c”,该函数就会返回1.c
- char *str_decompose(char *cmd)
- {
- strtok(cmd," ");
- cmd = strtok(NULL," ");
- return cmd;
- }
-
- void cmd_handle(int ret,struct Msg msg,int c_fd)
- {
- FILE *fp = NULL;
- int n_fread;
- char file_path[20] = "./"; //当前路径
- switch(ret){
- case PWD:
- fp = popen("pwd","r"); //调用终端执行pwd命令,并将数据存放到fp文件流中
- memset(msg.data,0,sizeof(msg.data));
- n_fread = fread(msg.data,1,sizeof(msg.data),fp);//读取文件流的数据
- msg.type = 0;
- write(c_fd,&msg,sizeof(msg)); //向客户端发送数据
- fflush(stdout); //刷新标准输出缓冲区,把输出缓冲区里的东西强制打印到标准输出设备上
- break;
- case LS:
- fp = popen("ls","r");
- memset(msg.data,0,sizeof(msg.data));
- n_fread = fread(msg.data,1,sizeof(msg.data),fp);
- msg.type = 0;
- write(c_fd,&msg,sizeof(msg));
- fflush(stdout);
- break;
- case CD:
- if(chdir(str_decompose(msg.cmd)) <0){ //修改当前工作目录
-
- perror("chdir");
- }
- break;
- case GET:
- strcat(file_path,str_decompose(msg.cmd));
- if(access(file_path,F_OK) < 0){ //判断服务器是否拥有客户端想要获取的文件
- perror("access");
- memset(msg.data,0,sizeof(msg.data));
- msg.type = 0;
- strcpy(msg.data,"Target file does not exist");
- write(c_fd,&msg,sizeof(msg));
- }else if(access(file_path,R_OK) < 0){ //判断服务器是否对该文件有读权限
- memset(msg.data,0,sizeof(msg.data));
- msg.type = 0;
- strcpy(msg.data,"The target file does not have read permission");
- write(c_fd,&msg,sizeof(msg));
- }else{ //获取该文件的内容,发送给客户端
- int file_fd = open(file_path,O_RDONLY,0600);
- if(file_fd < 0){
- perror("open");
- }
- int file_size = lseek(file_fd,0,SEEK_END);
- if(file_size < 0){
- perror("lseek");
- }
- lseek(file_fd,0,SEEK_SET);
- memset(msg.data,0,sizeof(msg.data));
- msg.type = GET;
- if(read(file_fd,msg.data,file_size) < 0){
- perror("read");
- }
- close(file_fd);
- write(c_fd,&msg,sizeof(msg));
- }
- break;
- case PUT:
- strcat(file_path,str_decompose(msg.cmd));
- int file_fd = open(file_path,O_RDWR|O_CREAT,0666); //创建一个文件,写入客户端想要存放的文件的数据
- if(file_fd < 0){
- perror("open");
- }
- if(write(file_fd,msg.data,strlen(msg.data)) < 0){
- perror("write");
- }
- close(file_fd);
- break;
- }
- }
-
-
-
- int main(int argc,char **argv)
- {
-
- struct sockaddr_in so_addr;
- struct sockaddr_in cl_addr;
-
- if(argc != 3){
- printf("Insufficient or inconsistent parameters\n");
- exit(-1);
- }
-
- memset(&so_addr,0,sizeof(struct sockaddr_in));
- memset(&cl_addr,0,sizeof(struct sockaddr_in));
-
- //1.socket
- int s_fd = socket(AF_INET,SOCK_STREAM,0);
- if(s_fd == -1){
- printf("socket is failusr\n");
- perror("socket");
- exit(-1);
- }
-
- so_addr.sin_family = AF_INET;
- so_addr.sin_port = htons(atoi(argv[2])); //将端口号转化成网络字节序
- inet_aton(argv[1],&so_addr.sin_addr); //将IP地址转化为网络字节序
-
- //2.bind
- int bd = bind(s_fd,(struct sockaddr *)&so_addr,sizeof(struct sockaddr_in));
- if(bd == -1){
- printf("bind is failusr\n");
- perror("bind");
- exit(-1);
- }
-
- //3.listen
- int ln = listen(s_fd,10);
- if(ln == -1){
- printf("listen is failusr\n");
- perror("listen");
- exit(-1);
- }
-
- int c_fd;
- int mark = 0;
- int clean = sizeof(struct sockaddr_in);
- pid_t pid;
- while(1){
- //4.accept
- c_fd = accept(s_fd,(struct sockaddr *)&cl_addr,&clean);
- if(c_fd == -1){
- printf("accept is failusr\n");
- perror("accept:");
- exit(-1);
- }
- mark++;
- printf("get No.%d connect: %s\n",mark,inet_ntoa(cl_addr.sin_addr));
-
- //连接成功后创建子进程接受客户端命令
- pid = fork();
- if(pid < 0){
- perror("fork");
- exit(-1);
- }
- else if(pid == 0){
- char *fp = NULL;
- struct Msg msg;
- int ret = 0;
- int c_read;
- while(1){
- memset(msg.cmd,0,sizeof(msg.cmd));
- c_read = read(c_fd,&msg,sizeof(msg)); //读取客户端发送的命令
- if(c_read <= 0){
- perror("read");
- break;
- }else{
- printf("get size is %d's cmd from NO.%d client:%s\n",c_read,mark,msg.cmd);
- ret = cmd_distinguish(msg.cmd); //对客户端传送的命令进行识别
- cmd_handle(ret,msg,c_fd); //对相关命令进行处理
-
- }
-
- }
- }
- close(c_fd);
- }
- close(s_fd);
-
- return 0;
- }
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
-
- struct Msg
- {
- int type;
- char cmd[50];
- char data[5120];
- };
-
- #define LLS 1
- #define LCD 2
- #define LPWD 3
- #define CD 4
- #define LQUIT 7
- #define PUT 8
- #define CMD 9
- #define QUIT 12
- #define LS 13
- #define PWD 14
- #define GET 15
-
-
- int cmd_distinguish(char *cmd)
- {
- int ret;
- cmd = strtok(cmd,"\n");
- if(!strcmp("lls",cmd)){
- ret = LLS;
- }else if(strstr(cmd,"lcd") != NULL){
- ret = LCD;
- }else if(!strcmp("lpwd",cmd)){
- ret = LPWD;
- }else if(!strcmp("ls",cmd)){
- ret = LS;
- }else if(!strcmp("lquit",cmd)){
- ret = LQUIT;
- }else if(strstr(cmd,"cd") != NULL){
- ret = CD;
- }else if(strstr(cmd,"get") != NULL){
- ret = GET;
- }else if(strstr(cmd,"put") != NULL){
- ret = PUT;
- }else if(!strcmp("pwd",cmd)){
- ret = PWD;
- }else{
- ret = 0;
- }
- return ret;
- }
-
-
- char *str_decompose(char *cmd)
- {
- strtok(cmd," ");
- cmd = strtok(NULL," ");
- return cmd;
- }
-
-
- int cmd_handle(int ret,struct Msg msg,int c_fd)
- {
-
- FILE *fp = NULL;
- int n_fread;
- char file_path[20] = "./";
- char tmp_cmd[50];
- switch(ret){
- case LPWD:
- printf("--------------------------------------\n");
- printf("\n");
- system("pwd"); //调用终端执行pwd命令,并将数据输出到标准输出上
- printf("\n");
- printf("--------------------------------------\n");
- printf("\n");
- break;
- case LLS:
- printf("--------------------------------------\n");
- printf("\n");
- system("ls"); //调用终端执行ls命令,并将数据输出到标准输出上
- printf("\n");
- printf("--------------------------------------\n");
- printf("\n");
- break;
- case LCD:
- if(chdir(str_decompose(msg.cmd)) < 0){//修改当前工作目录
- perror("chdir");
- }
- printf("\n");
- break;
- case LQUIT:
- printf("--------------------------------------\n");
- printf("\n");
- printf("client is quit\n");
- printf("\n");
- printf("--------------------------------------\n");
- printf("\n");
- exit(0);//退出当前进程
- break;
- case LS:
- msg.type = 0;
- write(c_fd,&msg,sizeof(msg)); //将用户输入发送给服务器,让服务器根据命令进行相应的行为
- break;
- case PWD:
- msg.type = 0;
- write(c_fd,&msg,sizeof(msg)); //将用户输入发送给服务器,让服务器根据命令进行相应的行为
- break;
- case CD:
- msg.type = 0;
- write(c_fd,&msg,sizeof(msg)); //将用户输入发送给服务器,让服务器根据命令进行相应的行为
- break;
- case GET:
- msg.type = 0;
- write(c_fd,&msg,sizeof(msg)); //将用户输入发送给服务器,让服务器根据命令进行相应的行为
- break;
- case PUT:
- memset(tmp_cmd,0,sizeof(tmp_cmd));
- strcpy(tmp_cmd,msg.cmd); //put 1.c ->tmp.cmd
- strcat(file_path,str_decompose(msg.cmd)); // ./1.c->file_path
- memset(msg.cmd,0,sizeof(msg.cmd));
- strcpy(msg.cmd,tmp_cmd);
- if(access(file_path,F_OK) < 0){ //判断客户端是否拥有想要存放到服务器的文件
- printf("--------------------------------------\n");
- printf("\n");
- printf("Target file does not exist\n");
- printf("\n");
- printf("--------------------------------------\n");
- printf("\n");
-
- }else if(access(file_path,R_OK) < 0){ //判断客户端是否对该文件有读权限
- printf("--------------------------------------\n");
- printf("\n");
- printf("The target file does not have read permission\n");
- printf("\n");
- printf("--------------------------------------\n");
- printf("\n");
- }else{ //获取该文件的内容,发送给服务器
- int pfile_fd = open(file_path,O_RDONLY,0666);
- if(pfile_fd < 0){
- perror("open");
- }
- int file_size = lseek(pfile_fd,0,SEEK_END);
- if(file_size < 0){
- perror("lseek");
- }
- lseek(pfile_fd,0,SEEK_SET);
- memset(msg.data,0,sizeof(msg.data));
- if(read(pfile_fd,msg.data,file_size) < 0){
- perror("read");
- }
- close(pfile_fd);
- write(c_fd,&msg,sizeof(msg));
- printf("--------------------------------------\n");
- printf("\n");
- printf("Target file is on server\n");
- printf("\n");
- printf("--------------------------------------\n");
- printf("\n");
- }
- break;
- default:
- printf("--------------------------------------\n");
- printf("\n");
- printf("Input error, please re-enter\n");
- printf("\n");
- printf("--------------------------------------\n");
- printf("\n");
- break;
-
- }
- return ret;
- }
-
- //对服务器发送的数据进行处理
- void from_socket_data_handle(struct Msg msg,int c_fd)
- {
- struct Msg socket_msg;
- int n_read;
- int file_fd;
- char file_path[20] = "./";
-
- n_read = read(c_fd,&socket_msg,sizeof(socket_msg));
- if(n_read == -1){
- perror("read socket");
- exit(-1);
- }else if(socket_msg.type == GET){ //如果是GET指令返回的数据,就存进文件中
- strcat(file_path,str_decompose(msg.cmd));
- file_fd = open(file_path,O_RDWR|O_CREAT,0666);
- write(file_fd,socket_msg.data,strlen(socket_msg.data));
- fflush(stdout);
- close(file_fd);
- printf("--------------------------------------\n");
- printf("\n");
- printf("%s\n","Get target file from server\n");
- printf("--------------------------------------\n");
- printf("\n");
- }else{ //如果是其他数据就直接打印出来
- printf("--------------------------------------\n");
- printf("\n");
- printf("%s\n",socket_msg.data);
- printf("\n");
- printf("--------------------------------------\n");
- printf("\n");
- }
-
- }
-
- int main(int argc,char **argv)
- {
- struct sockaddr_in c_addr;
- memset(&c_addr,0,sizeof(struct sockaddr_in));
-
- //1.socket
- int c_fd = socket(AF_INET,SOCK_STREAM,0);
- if(c_fd == -1){
- printf("socket is failusr\n");
- perror("socket");
- exit(-1);
- }
-
- c_addr.sin_family = AF_INET;
- c_addr.sin_port = htons(atoi(argv[2])); //将端口号转化成网络字节序
- inet_aton(argv[1],&c_addr.sin_addr); //将IP地址转化为网络字节序
-
- //2.connect
- if(connect(c_fd,(struct sockaddr *)&c_addr,sizeof(struct sockaddr_in)) == -1){
- perror("connect");
- exit(-1);
- }
-
- int n_read;
- struct Msg msg;
- int ret = 0;
- int mark = 0;
- int tmp = 0;
- while(1){
- memset(msg.cmd,0,sizeof(msg.cmd));
- memset(msg.data,0,sizeof(msg.data));
-
- fgets(msg.cmd,sizeof(msg.cmd),stdin); //获取用户输入的命令
- ret = cmd_distinguish(msg.cmd); //对用户键入的命令进行识别
- tmp = cmd_handle(ret,msg,c_fd); //对命令进行处理
- if(tmp > CMD){
- from_socket_data_handle(msg,c_fd); //对服务器传送的数据进行处理
- }
-
- fflush(stdout);
-
- }
- close(c_fd);
- return 0;
- }