远程访问服务器目录

1、设计
三个需要:
(1).协议
(2)客户端程序
(3)服务器端程序
2、协议
协议包含有请求和应答。首先,客户端发送一行包含有目录名称的请求。服务器读取该目录名之后打开并读取该目录,然后把文件列表发送到客户端。客户端循环地读取文件列表,直到服务器挂断连接产生文件结尾标志。
3、 客户端程序

#include<stdio.h>
#include<sys/types.h>
#include<string.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<netdb.h>
#include<unistd.h>
#include<stdlib.h>
#include<arpa/inet.h>

#define oops(msg) {perror(msg);exit(1);}
#define PORTNUM 15000

int main(int argc,char *argv[])
{
  struct sockaddr_in servaddr;
  int sock_id;
  char buff[BUFSIZ];
  int n_read;

  if(argc != 2)exit(1);
  sock_id = socket(AF_INET,SOCK_STREAM,0);

  if(sock_id == -1)
    oops("socket creat perror");

  servaddr.sin_family = AF_INET;
  servaddr.sin_port = htons(PORTNUM);
  servaddr.sin_addr.s_addr = inet_addr("192.168.1.127");

  if(connect(sock_id,(struct sockaddr*)&servaddr,sizeof(servaddr))!=0)
    oops("connect error");

  if(write(sock_id,argv[1],strlen(argv[1])) == -1)
    oops("write error");

  if(write(sock_id,"\n",1) == -1)
    oops("write error2");

  while((n_read = (int)read(sock_id,buff,BUFSIZ))>0)
  {
    if(write(1,buff,(size_t)n_read) == -1)
      oops("printf error");
    close(sock_id);
  }
  return 0;
}   

4、服务器端程序

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<netdb.h>
#include<time.h>
#include<strings.h>
#include<string.h>
#include<arpa/inet.h>
#include<ctype.h>

#define PORTNUM 15000
#define HOSTLEN 256
#define oops(msg) {perror(msg);exit(1);}
void sanitize(char *str)
{   
  char *src,*dest;
  for(src = dest = str;*src;src++)
    if(*src == '/'|| isalnum(*src))
      *dest++ = *src;

  *dest = '\0';
}   

int main()  
{
  struct sockaddr_in saddr;
  int sock_id,sock_fd;
  FILE *sock_fpi,*sock_fpo;
  FILE *pipe_fp;
  char dirname[BUFSIZ];
  char command[BUFSIZ];
  int c;

  sock_id = socket(PF_INET,SOCK_STREAM,0);
  if(sock_id == -1)
    oops("socket");

  saddr.sin_family = AF_INET;
  saddr.sin_port = htons(PORTNUM);
  saddr.sin_addr.s_addr = inet_addr("192.168.1.127");

  if(bind(sock_id,(struct sockaddr*)&saddr,sizeof(saddr))!=0)
    oops("bind error");

  if(listen(sock_id,1) != 0)
    oops("listen error");

  while(1)
  {
    sock_fd = accept(sock_id,NULL,NULL);

    if(sock_fd  == -1)
      oops("accept error");

    if((sock_fpi = fdopen(sock_fd,"r")) == NULL)
      oops("fdopen reading");

    if(fgets(dirname,BUFSIZ-5,sock_fpi) == NULL)
      oops("reading dirname");

    sanitize(dirname);

    if((sock_fpo = fdopen(sock_fd,"w")) == NULL)
      oops("fdopen write");

    sprintf(command,"ls %s",dirname);
    if((pipe_fp = popen(command,"r")) == NULL)

      oops("popen");

    while((c = getc(pipe_fp))!=EOF)
      putc(c,sock_fpo);

    pclose(pipe_fp);
    pclose(sock_fpo);
    pclose(sock_fpi);
  }
  return 0;
}   

服务器程序使用标准缓存流来读写数据。服务器用 fgets 调用从客户端读取目录
名。在调用 popen 后,服务器就像复制文件一样地使用 getc 和 putc 来传输数据。当然,服务器实际上是从本机上的进程向另一台机器上的进程复制数据。

**************************************************************************************对于任何运行参数中所含的命令或从因特网上获取数据的服务器,在编写的时候都要格外小心。程序中的服务器等待接收来自客户端的目录名,然后把它追加到 Is 命令的尾部如果有人发送字符串 “;rm “给服务器,服务器将创建并运行 “ls ; rm “命令了。为了减少被破坏的风险,程序中必须确保接收的字符串没有溢出输入缓存,也没有溢出给命令设置的缓存并且接收的目录名中不允许出现非法字符。 popen 系统调用对于编写网络服务来说是很危险的,因为它直接把-行字符串传给 shell 。在网络程序中,将字符串传给shell 是一个非常错误的想法。*


软件精灵:
Unix 服务器程序有短小、简洁的名字。很多服务器程序都是以d 结尾,如 httpd 、 inetd 、 syslogd 和 atd 。这里的 d 表示精灵 (daemon) 的意思,因而如名叫syslogd 的服务器程序实际上是系统日志精灵 (system log daemon) 。精灵就是一个为他人
提供服务的帮助者,它随时等待去帮助别人。输入命令 ps -el 或 ps -ax 就可以看到以字符 d 结尾的进程。然后,可以去阅读这些命令的帮助信息,从而可以更加深入地理解 Unix 中用客户/服务器模型是如何来处理一些基础操作的。大部分精灵进程都是在系统启动后就处于运行状态了。位于类似于 /etc/rc. d 目录中的 shell 脚本在后台启动了这些服务,它们的运行与终端相分离,时刻准备提供数据或服务。

总结:
•一些程序被作为单独的进程建立起来来接收和发送数据。在客户/服务器模型中,服务器进程为客户进程提供处理或数据服务。
•客户/服务器系统包含通信系统和协议。客户和服务器通过管道或 socket 进行通信。协议是会话过程中-系列规则的集合。
• popen 库函数可以将任何 shell 程序嵌入服务器程序并且让对服务器的访问就像访问缓存文件一样。
•管道是-对相连接的文件描述符。 socket 是一个未连接的通信端点,也是一个潜在
的文件描述符。客户进程通过把自己的 socket 和服务器端的 socket 相连来创建一
个通信连接。
• sockets 之间的连接可以扩展到另一台机器上。每个 socket 以机器地址和端口来
标识。
•到管道和 socket 的连接使用文件描述符。文件描述符为程序提供了与文件、设备和其他的进程通信的统一编程接口。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值