简单的 Client/Server 程序

本文详细解释了C/S架构的工作原理,包括客户端与服务器的分工、通信方式(RPC和SQL),以及服务器端(如创建ServerSocket)和客户端(如创建Socket)的典型操作流程。讨论了胖客户端应用特点和C/S架构的可扩展性。
摘要由CSDN通过智能技术生成
        C/S 架构全称为客户端 / 服务器体系结构,它是一种网络体系结构,其中客户端是用户运行应用程序的 PC 端或 者工作站,客户端要依靠服务器来获取资源。 C/S 架构是通过提供查询响应而不是总文件传输来减少了网络流 量。它允许多用户通过 GUI 前端更新到共享数据库,在客户端和服务器之间通信一般采用远程调用 RPC 或标准查询语言 SQL 语句。

C/S 架构的基本特征:胖客户端应用

        1、客户端进程包含特定于解决方案的逻辑,并提供用户与应用程序系统其余部分之间的接口。服务器进程充当管理共享资源(如数据库,打印机,调制解调器或高性能处理器)的软件引擎。
        2、前端任务和后端任务对计算资源有着根本不同的要求,例如处理器速度,内存,磁盘速度和容量以及输入 /输出设备。
        3、客户端和服务器的硬件平台和操作系统通常不相同。客户端和服务器进程通过一组明确定义的标准应用程序接口 API RPC 进行通信。
        C/S 架构的一个重要特征是可扩展性,它们可以水平或垂直缩放。水平扩展意味着添加或删除客户端,工作站只会对性能产生轻微影响。垂直扩展意味着迁移到更大更快的服务器计算机或多服务器中。

服务器端套路

1、创建 ServerSocket 对象,绑定监听端口。
2、通过 accept 方法监听客户端请求。
3、连接建立后,通过输入流读取客户端发送的请求信息。
4、通过输出流向客户端发送响应信息。
5、关闭响应的资源。
public class TimeServer {
    public static void main(String[] args) throws Exception{
        ServerSocket serverSocket = new ServerSocket(8080); 
//打开服务器的监听端口,客户端需要和服务器连接则必须确定端口号
        Socket accept = serverSocket.accept();
//阻塞当前进程,等待客户端的连接请求,如果连接创建成功则获取一个 Socket 对象
        //具体的处理逻辑
        InputStream is=accept.getInputStream();
        OutputStream os=accept.getOutputStream();
        BufferedReader br=new BufferedReader(new InputStreamReader(is));
 //针对字节流进行包装,简化编程
        String str=br.readLine(); 
//从输入流中获取客户端发送的数据,如果客户端发送的数据没有到达,则阻塞等待。接收到客户端发送的数据则将接收的数据返回
        System.out.println("Server:"+str);
        Date now=new Date(); 
//JDK1.8-版本的日期类型,当前一般建议使用 JDK1.8 引入的日期类型
        LocalDate... DateFormat df=new SimpleDateFormat("yyyy 年 M 月 d 日 E HH 点 mm 分 ss 秒");
        PrintWriter out=new PrintWriter(os);
        out.println("现在是:"+df.format(now));
        out.flush();
        accept.close();
        serverSocket.close();
    }
}

客户端套路

1、创建 Socket 对象,指明需要连接的服务器的地址和端口号。
2、连接建立后,通过输出流向服务器发送请求信息。
3、通过输入流获取服务器响应的信息。
4、关闭相应资源。
public class HelloClient {
    public static void main(String[] args) throws Exception {
        Socket client = new Socket("localhost", 8080);
//客户端发起连接请求,参数1为服务器的地址,参数2为连接端口号,也就是服务器的监听端口号
        InputStream is= client.getInputStream();
        OutputStream os= client.getOutputStream();
        PrintWriter out=new PrintWriter(os); 
//PrintWriter(OutputStream out, boolean autoFlush) 如果需要自动刷新缓冲区,则构建时可以添加 boolean 类型参数
        out.println("Hello Server!"); //客户端向服务器发送字符串数据
        out.flush();
        BufferedReader br=new BufferedReader(new InputStreamReader(is));
//客户端接收服务器的响应信息,如果服务器没有发送,则阻塞等待
        String res=br.readLine();
        System.out.println("Client:"+res);
        client.close();
    }
}

 

  • 7
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是一个简单的 Rust gRPC 服务器和客户端程序,用于传输大于1GB的文件。 首先,您需要安装 `grpcio` 和 `grpcio-protoc-gen` 依赖项: ```bash $ cargo install grpcio grpcio-protoc-gen ``` 接下来,您需要编写 `.proto` 文件,用于定义 gRPC 服务和消息格式。下面是一个示例 `.proto` 文件,用于定义服务和消息格式: ```protobuf syntax = "proto3"; package filetransfer; service FileTransferService { rpc UploadFile(stream FileChunk) returns (FileUploadResponse) {} } message FileChunk { bytes data = 1; } message FileUploadResponse { string message = 1; } ``` 接下来,使用以下命令生成 Rust 代码: ```bash $ grpcio-protoc --rust_out=. --grpc_out=. --plugin=protoc-gen-grpc=`which grpc_rust_plugin` filetransfer.proto ``` 现在,您可以编写 Rust 服务器代码: ```rust use std::io::{self, Write}; use std::sync::Arc; use grpcio::{Environment, RpcContext, ServerBuilder, UnarySink}; use protobuf::{CodedInputStream, CodedOutputStream}; use filetransfer::{FileChunk, FileTransferService, FileUploadResponse}; #[derive(Clone)] struct FileTransferServiceImpl; impl FileTransferService for FileTransferServiceImpl { fn upload_file( &mut self, ctx: RpcContext<'_>, stream: grpcio::RequestStream<FileChunk>, sink: UnarySink<FileUploadResponse>, ) { let mut file_data: Vec<u8> = Vec::new(); for chunk in stream { let chunk = chunk.unwrap(); file_data.extend_from_slice(&chunk.data[..]); } let response = FileUploadResponse { message: format!("Uploaded {} bytes", file_data.len()), }; let f = sink .success(response) .map_err(move |e| println!("failed to reply {:?}: {:?}", file_data, e)) .map(|_| ()); ctx.spawn(f) } } fn main() { let env = Arc::new(Environment::new(1)); let service = create_file_transfer_service(); let mut server = ServerBuilder::new(env) .register_service(service) .bind("0.0.0.0", 50051) .build() .unwrap(); server.start(); for &(ref host, port) in server.bind_addrs() { println!("listening on {}:{}", host, port); } loop { std::thread::park(); } } fn create_file_transfer_service() -> FileTransferServiceServer<FileTransferServiceImpl> { FileTransferServiceServer::new(FileTransferServiceImpl {}) } ``` 这个服务器会监听在本地的 50051 端口,等待客户端连接。一旦连接建立,它会接受 `FileChunk` 流,并将它们写入一个 `Vec<u8>` 缓冲区中。一旦读取完整个文件,它将打印文件大小并发送一个 `FileUploadResponse` 结构体作为响应。 现在,您可以编写 Rust 客户端代码: ```rust use std::fs::File; use std::io::{self, Read}; use std::path::Path; use grpcio::{ChannelBuilder, EnvBuilder}; use filetransfer::{FileChunk, FileTransferServiceClient}; fn main() { let env = EnvBuilder::new().build(); let channel = ChannelBuilder::new(env).connect("localhost:50051"); let client = FileTransferServiceClient::new(channel); let mut file = File::open(Path::new("/path/to/large/file")).unwrap(); let mut buffer = [0; 1024 * 1024]; // 1MB buffer let mut total_bytes_read = 0; loop { let bytes_read = file.read(&mut buffer).unwrap(); if bytes_read == 0 { break; } let chunk = FileChunk { data: buffer[..bytes_read].to_vec(), }; client.upload_file(&chunk).unwrap(); total_bytes_read += bytes_read; println!("Uploaded {} bytes", total_bytes_read); } } ``` 这个客户端会打开指定的文件,并将它们分成 1MB 的块,将每个块作为 `FileChunk` 发送到服务器。一旦读取完整个文件,它将打印已上传的总字节数。 这就是一个基本的 Rust gRPC 客户端/服务器程序,用于传输大于 1GB 的文件。您可以根据需要修改代码,以适应不同的需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值