基于TCP/IP的文件服务器编程一例

来源,华清远见嵌入式学院实验手册,代码来源:华清远见曾宏安

实现的功能:

编写TCP文件服务器和客户端。客户端可以上传和下载文件

客户端支持功能如下:

1.支持一下命令

help 显示客户端所有命令和说明

list  显示服务器端可以下载的文件列表

get <filename> 下载文件

put <filename> 上传文件

quit 退出客户端

 

服务器端功能(单进程)

解析客户端的命令并提供相应的服务

 

服务器流程:

 

 

 

服务器端的代码:

   1:  #include <stdio.h>
   2:  #include <stdlib.h>
   3:  #include <unistd.h>
   4:  #include <string.h>
   5:  #include <fcntl.h>
   6:  #include <dirent.h>
   7:  #include <sys/socket.h>
   8:  #include <netinet/in.h>
   9:  #include <arpa/inet.h>
  10:   
  11:  #define N  256
  12:   
  13:  typedef struct sockaddr SA;  //
  14:   
  15:  void do_list(int connfd)
  16:  {
  17:      DIR *mydir;
  18:      struct dirent *dp;
  19:   
  20:      if ((mydir = opendir(".")) == NULL)   //打开当前目录
  21:      {
  22:          perror("fail to opendir");
  23:          return;
  24:      }
  25:      while ((dp = readdir(mydir)) != NULL)  //读目录,每次返回一项, 读完时,返回空
  26:      {
  27:          if (dp->d_name[0] != '.')  //将.和..以及隐藏文件跳过
  28:          {
  29:              send(connfd, dp->d_name, N, 0);  //为了便于客户端将每次发送的目录项区分开,服务器每次发N个,相应的客户端也受N个
  30:          }
  31:      }
  32:      closedir(mydir);   //关闭目录
  33:  }
  34:   
  35:  void do_get(int connfd, char fname[]) //下载请求处理函数
  36:  {
  37:      int fd, nbyte;
  38:      char buf[N];
  39:   
  40:      if ((fd = open(fname, O_RDONLY)) < 0)  //以只读方式打开,假如不存在,报错
  41:      {
  42:          perror("fail to open");
  43:          send(connfd, "N", 1, 0);  //向客户端发送‘N',表示文件不存在,发送1个,客户端也收1个
  44:          return; 退出下载请求处理函数,注:服务器不能退出
  45:      }
  46:      send(connfd, "Y", 1, 0);  //向客户端发送Y,表示文件存在
  47:      while ((nbyte = read(fd, buf, N)) > 0)  //读文件,读完了返回空
  48:      {
  49:          send(connfd, buf, nbyte, 0);  //发送文件原则:读多少,就发多少!
  50:      }
  51:      close(fd);
  52:  }
  53:   
  54:  void do_put(int connfd, char fname[])  //上传请求处理函数
  55:  {
  56:      int fd, nbyte;
  57:      char buf[N];
  58:   
  59:      if ((fd = open(fname, O_WRONLY | O_CREAT | O_EXCL, 0666)) < 0)  //不存在创建,存在报错
  60:      {
  61:          perror("fail to open");
  62:          send(connfd, "N", 1, 0);  //向客户端发送‘N',表示文件已存在,发送1个,客户端也收1个
  63:          return;
  64:      }
  65:      send(connfd, "Y", 1, 0);//向客户端发送‘N',表示文件不存在,可以上传。发送1个,客户端也收1个
  66:      while ((nbyte = recv(connfd, buf, N, 0)) > 0)
  67:      {
  68:          write(fd, buf, nbyte);  //写文件原则:接收多少,就写多少
  69:      }
  70:      close(fd);
  71:  }
  72:   
  73:  int main(int argc, char *argv[])
  74:  {
  75:      int listenfd, connfd;
  76:      char command[N];
  77:      struct sockaddr_in myaddr, peeraddr;
  78:      socklen_t peerlen = sizeof(peeraddr);
  79:   
  80:      if (argc < 3)
  81:      {
  82:          printf("Usage : %s <ip> <port>\n", argv[0]);
  83:          return -1;
  84:      }
  85:   
  86:      // XXX int socket(int domain, int type, int protocol);
  87:      if ((listenfd = socket(PF_INET, SOCK_STREAM, 0)) < 0)
  88:      {
  89:          perror("fail to socket");
  90:          exit(-1);
  91:      }
  92:   
  93:      bzero(&myaddr, sizeof(myaddr));
  94:      myaddr.sin_family = PF_INET;
  95:      myaddr.sin_port = htons(atoi(argv[2])); 
  96:      myaddr.sin_addr.s_addr = inet_addr(argv[1]);
  97:      // XXX int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
  98:      if (bind(listenfd, (SA *)&myaddr, sizeof(myaddr)) < 0)
  99:      {
 100:          perror("fail to bind");
 101:          exit(-1);
 102:      }
 103:   
 104:      if (listen(listenfd, 5) < 0)
 105:      {
 106:          perror("fail to listen");
 107:          exit(-1);
 108:      }
 109:   
 110:      while ( 1 )
 111:      {
 112:          // XXX int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
 113:          if ((connfd = accept(listenfd, (SA *)&peeraddr, &peerlen)) < 0)
 114:          {
 115:              perror("fail to accept");
 116:              exit(-1);
 117:          }
 118:          printf("connection from [%s:%d]\n", inet_ntoa(peeraddr.sin_addr), ntohs(peeraddr.sin_port));
 119:          recv(connfd, command, N, 0);  // recv command from client,简单处理,客户端发N个,服务器也应该收N个
 120:          switch ( command[0] )  //因为客户端发来的命令第一个字符就是命令类型
 121:          {
 122:          case 'L':  //客户端的列表请求
 123:              printf("do_list\n");
 124:              do_list(connfd);
 125:              break;
 126:          case 'G':  //客户端的下载请求
 127:              do_get(connfd, command+1);
 128:              break;
 129:          case 'P': //客户端的上传请求
 130:              do_put(connfd, command+1);
 131:              break;
 132:          }
 133:          close(connfd);  //关闭本次的连接套接字
 134:      }
 135:   
 136:      return 0;
 137:  }

 客户端流程:

 

客户端的代码:

   1:  #include <stdio.h>
   2:  #include <stdlib.h>
   3:  #include <unistd.h>
   4:  #include <string.h>
   5:  #include <fcntl.h>
   6:  #include <sys/socket.h>
   7:  #include <netinet/in.h>
   8:  #include <arpa/inet.h>
   9:   
  10:  #define  N  256
  11:   
  12:  typedef struct sockaddr SA;
  13:   
  14:  void do_help()
  15:  {
  16:      printf("      help : display help info\n");
  17:      printf("      list : get file list from server\n");
  18:      printf("get <file> : download <file> from server\n");
  19:      printf("put <file> : upload <file> to server\n");
  20:      printf("      quit : exit\n");
  21:  }
  22:   
  23:  void do_list(struct sockaddr_in servaddr)      //list命令处理函数
  24:  {
  25:      int sockfd;
  26:      char buf[N];
  27:   
  28:      if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) < 0)
  29:      {
  30:          perror("fail to socket");
  31:          exit(-1);
  32:      }
  33:   
  34:          // XXX int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
  35:      if (connect(sockfd, (SA *)&servaddr, sizeof(servaddr)) < 0)
  36:      {
  37:          perror("fail to connect");
  38:          exit(-1);
  39:      }
  40:      
  41:      buf[0] = 'L';         //向服务器发送字符'L',表示list命令
  42:      send(sockfd, buf, N, 0);  // send command to server,发送字节数N最好与服务器那边对应起来,发多少,收多少
  43:      while (recv(sockfd, buf, N, 0) > 0) //简单处理,服务器每次发N个,那么客户端每次也应该收N个,这样就把每个目录项区分开了
  44:      {
  45:          printf(" %s\n", buf);
  46:      }
  47:      close(sockfd); //关闭套接字
  48:  }
  49:   
  50:  void do_get(struct sockaddr_in servaddr, char fname[])  //下载处理函数
  51:  {
  52:      int sockfd, fd, nbyte;
  53:      char buf[N];
  54:   
  55:      if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) < 0)
  56:      {
  57:          perror("fail to socket");
  58:          exit(-1);
  59:      }
  60:   
  61:          // XXX int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
  62:      if (connect(sockfd, (SA *)&servaddr, sizeof(servaddr)) < 0)
  63:      {
  64:          perror("fail to connect");
  65:          exit(-1);
  66:      }
  67:   
  68:      sprintf(buf, "G%s", fname);  //将上传标识符'G'和文件名格式化输出到缓冲区buf中,想法很好!
  69:      send(sockfd, buf, N, 0);  // send command to server  //将客户端的上传命令连同文件名一块发给服务器。
  70:      //等待服务器的确认回复,因为要下载的文件名可能在服务器上不存在,服务器发送了1个,所以客户端也应该接收至少1个。
  71:      recv(sockfd, buf, 1, 0);  // recv reply from server  
  72:      if (buf[0] == 'N')  //服务器返回N,说明服务器上没有客户端要下载的文件
  73:      {
  74:          printf("can't open %s on server\n", fname);
  75:          close(sockfd);  //关闭套接字
  76:          return;  //退出下载处理函数
  77:      }
  78:      if ((fd = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0) //不存在创建,存在清除
  79:      {
  80:          perror("fail to open");
  81:          close(sockfd);
  82:          return;
  83:      }
  84:      while ((nbyte = recv(sockfd, buf, N, 0)) > 0)  //接收服务器发送的文件内容 
  85:      {
  86:          write(fd, buf, nbyte);  //写文件原则:收多少,就写到少!
  87:      }
  88:      close(fd);   //关闭文件描述符
  89:      close(sockfd);
  90:  }
  91:   
  92:  void do_put(struct sockaddr_in servaddr, char fname[]) //上传处理函数
  93:  {
  94:      int sockfd, fd, nbyte;
  95:      char buf[N];
  96:   
  97:      if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) < 0)
  98:      {
  99:          perror("fail to socket");
 100:          exit(-1);
 101:      }
 102:   
 103:          // XXX int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
 104:      if (connect(sockfd, (SA *)&servaddr, sizeof(servaddr)) < 0)
 105:      {
 106:          perror("fail to connect");
 107:          exit(-1);
 108:      }
 109:   
 110:      sprintf(buf, "P%s", fname);//将下载标识符'P'和文件名格式化输出到缓冲区buf中,想法很好!
 111:      send(sockfd, buf, N, 0);  // send command to server//将客户端的下载命令连同文件名一块发给服务器。
 112:      //等待服务器的确认回复,因为要上传的文件名可能在服务器上已经存在。服务器发送了1个,所以客户端也应该接收至少1个。
 113:      recv(sockfd, buf, 1, 0);  // recv reply from server
 114:      if (buf[0] == 'N') //服务器返回N,说明服务器上有客户端要上传的文件
 115:      {
 116:          printf("%s exsit on server,\n", fname);
 117:          close(sockfd);
 118:          return;
 119:      }
 120:      if ((fd = open(fname, O_RDONLY)) < 0)
 121:      {
 122:          perror("fail to open");
 123:          close(sockfd);
 124:          return;
 125:      }
 126:      while ((nbyte = read(fd, buf, N)) > 0) 
 127:      {
 128:          send(sockfd, buf, nbyte,0);  //发送文件原则:从文件流中读多少,就向服务器发多少!
 129:      }
 130:      close(fd);
 131:      close(sockfd);
 132:  }
 133:   
 134:  int main(int argc, char *argv[])
 135:  {
 136:      int sockfd;
 137:      char command[N];
 138:      struct sockaddr_in servaddr;
 139:   
 140:      if (argc < 3)
 141:      {
 142:          printf("Usage : %s <ip> <port>\n", argv[0]);
 143:          return -1;
 144:      }
 145:   
 146:      bzero(&servaddr, sizeof(servaddr));
 147:      servaddr.sin_family = PF_INET;
 148:      servaddr.sin_port = htons(atoi(argv[2]));
 149:      servaddr.sin_addr.s_addr = inet_addr(argv[1]);
 150:   
 151:  #if 0
 152:      // XXX int socket(int domain, int type, int protocol);
 153:      #endif
 154:      while ( 1 )
 155:      {
 156:          printf("client > ");
 157:          fgets(command, N, stdin);
 158:          command[strlen(command)-1] = '\0';  //将'\0'前面的'\n'用'\0'覆盖。
 159:          if (strncmp(command, "help", 4) == 0)
 160:          {
 161:              do_help();
 162:          }
 163:          else if (strncmp(command, "list", 4) == 0)
 164:          {
 165:              do_list(servaddr);
 166:          }
 167:          else if (strncmp(command, "get", 3) == 0)
 168:          {
 169:              do_get(servaddr, command+4);
 170:          }
 171:          else if (strncmp(command, "put", 3) == 0)
 172:          {
 173:              do_put(servaddr, command+4);
 174:          }
 175:          else if (strncmp(command, "quit", 4) == 0)
 176:          {
 177:              printf("bye\n");
 178:              exit(0);
 179:          }
 180:          else
 181:          {
 182:              printf(" invalid command %s\n", command);
 183:              do_help();
 184:          }
 185:      }
 186:   
 187:      return 0;
 188:  }

转载于:https://www.cnblogs.com/pengdonglin137/archive/2013/03/13/2958192.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/360914.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Linux系统基础】(2)在Linux上部署MySQL、RabbitMQ、ElasticSearch、Zookeeper、Kafka、NoSQL等各类软件

实战章节&#xff1a;在Linux上部署各类软件 前言 为什么学习各类软件在Linux上的部署 在前面&#xff0c;我们学习了许多的Linux命令和高级技巧&#xff0c;这些知识点比较零散&#xff0c;同学们跟随着课程的内容进行练习虽然可以基础掌握这些命令和技巧的使用&#xff0c;…

JDK 7和JDK 8中大行读取速度较慢的原因

我之前发布了博客文章“使用JDK 7和JDK 8读取慢速行”&#xff0c;并且在该问题上有一些有用的评论来描述该问题。 这篇文章提供了更多解释&#xff0c;说明为何该文章中演示的文件读取&#xff08;并由Ant的LineContainsRegExp使用 &#xff09;在Java 7和Java 8中比在Java 6中…

Spring Stateless State Security第3部分:JWT +社会认证

我的Stateless Spring Security系列文章的第三部分也是最后一部分是关于将基于JWT令牌的身份验证与spring-social-security混合在一起的。 这篇文章直接建立在此基础上&#xff0c;并且主要集中在已更改的部分上。 想法是使用基于OAuth 2的“使用Facebook登录”功能来替换基于用…

nyoj239 月老的难题 二分图 匈牙利算法

月老的难题 时间限制&#xff1a;1000 ms | 内存限制&#xff1a;65535 KB难度&#xff1a;4描述月老准备给n个女孩与n个男孩牵红线&#xff0c;成就一对对美好的姻缘。 现在&#xff0c;由于一些原因&#xff0c;部分男孩与女孩可能结成幸福的一家&#xff0c;部分可能不会结…

Web应用程序体系结构– Spring MVC – AngularJs堆栈

Spring MVC和AngularJs共同为构建表单密集型Web应用程序提供了一个真正高效且吸引人的前端开发堆栈。在这篇博客文章中&#xff0c;我们将看到如何使用这些技术构建表单密集型Web应用程序&#xff0c;并将这种方法与其他方法进行比较可用选项。 可以在此github 存储库中找到功能…

antd Datepicker组件报错 ——date.clone is not a function或者date1.isAfter is not a function

问题描述&#xff1a; antd Datepicker组件报错 ——date.clone is not a function或者date1.isAfter is not a function 原因分析&#xff1a; 在From中渲染默认值&#xff0c;一般数据请求拿到返回值存在异步&#xff0c;会晚于渲染&#xff0c;因此日期转换不能放在DatePi…

集成CDI和WebSockets

考虑尝试一个简单的Java EE 7原型应用程序&#xff0c;该应用程序涉及JAX-RS&#xff08;REST&#xff09;&#xff0c;WebSockets和CDI。 注意 &#xff1a;不想让它成为破坏者-但这篇文章主要讨论了我在尝试使用Web套接字和使用CDI作为“胶水”的REST&#xff08;在Java EE应…

Java中连接字符串的最佳方法

最近有人问我这个问题–在Java中使用运算符连接字符串是否对性能不利&#xff1f; 这让我开始思考Java中连接字符串的不同方法&#xff0c;以及它们如何相互对抗。 这些是我要研究的方法&#xff1a; 使用运算符 使用StringBuilder 使用StringBuffer 使用String.concat() …

十大最常见的Java性能问题

Java性能是所有Java应用程序开发人员都关心的问题&#xff0c;因为快速使应用程序与使其正常运行同等重要。 史蒂文海恩斯&#xff08;Steven Haines&#xff09;使用他在Java性能问题上的个人经验得出的结论是&#xff0c; 大多数问题都有共同的根本原因 。 因此&#xff0c;作…

Unity3D 访问Access数据库

Unity3D 访问Access数据库 在开始这个小教程之前呢&#xff0c;其实在网上你已经可以找到相关的资料了&#xff0c;但是我还是要把我自己做练习的一点东西分享出来。写这个教程的主要原因呢&#xff0c;是一个朋友在u3d的官网论坛里&#xff0c;找到了这个demo&#xff0c;但是…

LaTeX 基础笔记。开篇

LaTeX 的起源非常牛逼&#xff0c;有一套书大家可能听说过《计算机程序设计艺术》&#xff0c;写了好几本。当然能在计算机方面写上艺术俩字的书恐怕不是我们一般人能读懂得东西了。他的作者在1976年准备写第二卷的时候发现计算机的排版非常难看&#xff0c;所以&#xff0c;为…

Java旧版不断发展

我最近偶然发现了JDK API的一个非常有趣的警告&#xff0c;即Class.getConstructors()方法。 它的方法签名是这样的&#xff1a; Constructor<?>[] getConstructors()有趣的是&#xff0c; Class.getConstructor(Class...)返回一个Constructor<T> &#xff0c;并…

带Lambda表达式的Apache Wicket

这是怎么回事&#xff1f; :) 我一直在从事一些项目&#xff0c;这些项目值得庆幸的是将Apache Wicket用于表示层。 我自然想到Java的8个lambda表达式如何与Wicket完美匹配。 而不仅仅是我&#xff0c; Wicket团队似乎已经在努力更改API&#xff0c;以为开箱即用的lambda提供支…

装饰者模式如何拯救了我的一天

在工作中&#xff0c;我正在处理庞大的Java代码库&#xff0c;该代码库是由许多不同的开发人员在15年的时间里开发的。 并不是所有的事情都由书来完成&#xff0c;但是同时我通常没有机会重构遇到的每一个奇怪之处。 尽管如此&#xff0c;仍可以每天采取提高代码质量的措施。 …

快速的骆驼和云消息传递

Apache Camel是一个流行的&#xff0c;成熟的开源集成库。 它实现了企业集成模式 &#xff0c;这是在集成分布式系统时经常出现的一组模式。 过去&#xff0c;我写过很多关于Camel的文章&#xff0c; 包括为什么我比Spring Integration更喜欢它 &#xff0c; 路由引擎 如何 工作…

三角形类1

/* 程序的版权和版本声明部分 Copyright (c)2012, 烟台大学计算机学院学生 All rightsreserved. 文件名称&#xff1a; object.cpp 作者&#xff1a;刘清远 完成日期&#xff1a; 2013年3月29日 版本号&#xff1a; v1.0 输入描述&#xff1a;无 问题描述&#xff1a;设计求三…

android 自定义xml属性

Android 自定义组件 Android 提供了非常精致的和非常强大的组件化模型&#xff0c;能够更加方便的构建UI,这些UI组件都是基于基本的layout类:View 和 ViewGroup。 部分能够用的widgets包括&#xff1a;Button&#xff0c;TextView,EditText,ListView,CheckBox&#xff0c;Radio…

LeetCode: Longest Common Prefix

string.erase没掌握好&#xff0c;悲了个剧&#xff0c;2次过 1 class Solution {2 public:3 string longestCommonPrefix(vector<string> &strs) {4 // Start typing your C/C solution below5 // DO NOT write int main() function6 s…

流式传输大数据:Storm,Spark和Samza

有许多分布式计算系统可以实时或近实时处理大数据。 本文将从对三个Apache框架的简短描述开始&#xff0c;并试图对它们之间的某些相似之处和不同之处提供一个快速的高级概述。 阿帕奇风暴 在风暴 &#xff0c;你设计要求的T opology实时计算的图&#xff0c;然后喂到集群&…

uniapp使用阿里云多色图标

下载&#xff0c;然后解压 输入cmd&#xff0c;然后enter 输入 npm install -g iconfont-tools 再输入 iconfont-tools&#xff0c;然后一直enter&#xff0c;直到结束 目录会多了个iconfont-weapp文件&#xff0c;点击去找到 iconfont-weapp-icon.css 导入和使用 t-icon开头 接…