首先实现简单的服务器端代码如下:
- package cn.xaut.ftp;
- import java.io.DataInputStream;
- import java.io.FileOutputStream;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.OutputStream;
- import java.net.ServerSocket;
- import java.net.Socket;
- public class ChatServer {
-
- public static void main(String[] args) {
- ChatServer cs =new ChatServer();
- cs.setUpServer(9090);
- }
- private void setUpServer(int port) {
- try {
- ServerSocket server =new ServerSocket(port);
- System.out.println("服务器创建成功!"+port);
-
- while(true){
- Socket client =server.accept();
- System.out.println("Incoming client:"+client.getRemoteSocketAddress());
- //调用处理连接对象的方法去处理连接
- processChat(client);
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- //处理客户端进入的连接对象
- private void processChat(Socket client) {
- try {
- OutputStream out =client.getOutputStream();
- InputStream ins=client.getInputStream();
- //将输入流包装为DataInputStream方便读取原始类型的流
- DataInputStream dins=new DataInputStream(ins);
- while(true){
- //开始读取数据,没一条消息,总是以一个int开头
- //1.读消息长度,readInt()方法底层从流中读取4个字节,组成一个int
- int totalLen=dins.readInt();
- System.out.println("*********进入一条消息总长:"+totalLen);
- //2.读取消息类型标识,只读取一个字节
- byte flag =dins.readByte();
- System.out.println("消息接收类型为:"+flag);
- //3.读取目标客户号码,一个int
- int destNum =dins.readInt(); //消息头解析完毕
- System.out.println("消息接收目标用户号是:"+destNum);
-
- //根据消息的类型,读取消息体部分
- if(flag==1){
- byte[] data=new byte[totalLen-4-1-4];
- //从流中读取data.length个字节放入数组中
- dins.readFully(data);
- String msg=new String(data); //转成字符串
- System.out.println("发送文本给"+destNum+" 内容是:"+msg);
- }else if(flag==2){ //文件数据包体解析
- System.out.println("发送文件给:"+destNum);
- byte[] data=new byte[256];
- dins.readFully(data); //读取256个字节做文件名字
- //解析出了文件名字,并去除末尾空格
- String fileName =new String(data).trim();
- System.out.println("读到的文件名字是:"+fileName);
- //余下的字节就是文件内容
- data =new byte[totalLen-4-1-4-256]; //文件字节数据总长
- dins.readFully(data); //读入文件的字节
- //保存文件到当前目录下
- FileOutputStream fous=new FileOutputStream(fileName);
- fous.write(data);
- fous.flush();
- fous.close();
- System.out.println("文件保存完成!");
- }else{
- System.out.println("收到未知数据包!"+flag);
- client.close();
- }
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
-
- }
- }
简单的客户端代码如下:
- package cn.xaut.ftp;
- import java.io.*;
- import java.net.Socket;
- import java.net.UnknownHostException;
- import java.util.Scanner;
- public class ChatClient {
- private DataOutputStream dous; //输出流对象
- /**
- * 向流中写入定长字节,如果不足,补二进制0
- * @param out:要写入的流
- * @param str:字符串
- * @param len:要写入的长度
- */
- public static void main(String[] args) {
- ChatClient qqc=new ChatClient();
- qqc.conn2Server("localhost", 9090);
- }
-
- private void writeString(DataOutputStream out,String str,int len){
- byte[] data=str.getBytes();
- try {
- out.write(data);
- //假设都是短,需要补0
- while(len>data.length){
- out.writeByte('\0'); //补二进制0
- len--;
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
-
- /**
- * 发送一条文本消息
- * @param msg:消息内容
- * @param destNum:接收者号码
- * 打包的过程
- */
- private void sendTextMsg(String msg,int destNum){
- try {
- byte[] strb=msg.getBytes(); //得到消息的字节数
- int totalLen=4+1+4+strb.length;
- System.out.println("发送总 长度为:"+totalLen);
- dous.writeInt(totalLen); //总长
- dous.writeByte(1); //类型:1为文本消息
- dous.writeInt(destNum); //写入目标用户号
- dous.write(strb); //写入消息内容
- dous.flush();
-
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
-
- /**
- * 发送一个文件数据包
- * @param fileName:文件绝对路径名
- * @param destNum: 目标用户号码
- */
- private void sendFileMsg(String fileName,int destNum){
- try {
- //根据文件名创建文件对象
- File file =new File(fileName);
- //根据文件对象,构造一个输入流
- InputStream ins=new FileInputStream(file);
- int fileDataLen =ins.available(); //文件数据总长
- int totalLen =4+1+4+256+fileDataLen; //得到了要发送数据包的总长
- dous.writeInt(totalLen);
- dous.writeByte(2); //类型:2,即文件数据包
- //写入目标用户号
- dous.writeInt(destNum);
- //文件名:得到文件的短名字
- String shortFileName =file.getName();
- //写入文件名,不足256个长度时,补\0
- writeString(dous,shortFileName,256);
- byte[] fileData =new byte[fileDataLen];
- ins.read(fileData); //读入文件数据
- dous.write(fileData); //写出到服务器的流中
- dous.flush(); //刷新流
-
- }catch (FileNotFoundException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
-
- public void conn2Server(String ip,int port){
- //创建一个到服务器端的Socket对象
- try {
- Socket client =new Socket(ip,port);
- //得到输入输出流对象
- InputStream ins =client.getInputStream();
- OutputStream out=client.getOutputStream();
- //将输出流包装为DataOutputStream对象
- dous=new DataOutputStream(out);
-
- int testCount=0;
- while(true){
- System.out.println("登录服务器成功,请选择你要发送的类型(1:聊天 2:文件)");
- //让用户从命令行输入要发送的文件名字
- Scanner sc=new Scanner(System.in);
- int type=sc.nextInt();
-
- if(type==1){ //发文本
- sendTextMsg("abc聊天内容"+testCount,8888);
- }
- if(type==2){ //发文件,注这个文件必须存在
- sendFileMsg("e://1.jpg",8888);
- }
- testCount++;
- }
- } catch (UnknownHostException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
以上示例了简单的协议制定、实现思路及方法。我们将消息数据按协议规则写入到流中的过程称之为“打包”过程,从流中读取的过程称之为“解包”过程。
在线JavaDoc:(中文版)
附件:
FTP.zip 经典文件传输:
文件传输系统.rar
阅读(1252) | 评论(0) | 转发(0) |