博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
基于TCP/IP的文件服务器编程一例
阅读量:6133 次
发布时间:2019-06-21

本文共 10277 字,大约阅读时间需要 34 分钟。

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

实现的功能:

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

客户端支持功能如下:

1.支持一下命令

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

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

get <filename> 下载文件

put <filename> 上传文件

quit 退出客户端

 

服务器端功能(单进程)

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

 

服务器流程:

 

 

 

服务器端的代码:

1:  #include 
2:  #include 
3:  #include 
4:  #include 
5:  #include 
6:  #include 
7:  #include 
8:  #include 
9:  #include 
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 
\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 
2:  #include 
3:  #include 
4:  #include 
5:  #include 
6:  #include 
7:  #include 
8:  #include 
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 
: download
from server\n");
19:      printf("put 
: upload
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 
\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:  }

转载地址:http://elxua.baihongyu.com/

你可能感兴趣的文章
【总结整理】JQuery基础学习---样式篇
查看>>
查询个人站点的文章、分类和标签查询
查看>>
基础知识:数字、字符串、列表 的类型及内置方法
查看>>
JSP的隐式对象
查看>>
JS图片跟着鼠标跑效果
查看>>
[SCOI2005][BZOJ 1084]最大子矩阵
查看>>
学习笔记之Data Visualization
查看>>
Leetcode 3. Longest Substring Without Repeating Characters
查看>>
【FJOI2015】金币换位问题
查看>>
数学之美系列二十 -- 自然语言处理的教父 马库斯
查看>>
Android实现自定义位置无标题Dialog
查看>>
面试总结
查看>>
Chrome浏览器播放HTML5音频没声音的解决方案
查看>>
easyui datagrid 行编辑功能
查看>>
HDU 2818 (矢量并查集)
查看>>
实验二 Java面向对象程序设计
查看>>
------__________________________9余数定理-__________ 1163______________
查看>>
webapp返回上一页 处理
查看>>
新安装的WAMP中phpmyadmin的密码问题
查看>>
20172303 2017-2018-2 《程序设计与数据结构》第5周学习总结
查看>>