socket客服交互及文件传输的简单实现

整体思路:1.服务端:多线程接受客户端。由clienthandler实现Runnable接口,并采用有参构造,参数为Socket。clienthandler的run方法阻塞读取客户端的消息,并判断消息类型,做出判断。若为chat,则服务端返回客户端的消息,若为file则新建线程传入文件名和文件长度接受文件。2.客户端:客户端监听控制台输入,输入格式为mess:+信息或者file:源文件绝对路径。内部类liunnablestener继承Runnable监听服务端返回消息。
第三方包:XStream包。(如果你的jdk大于1.8则最好使用版本高点的包,低版本不适用lmbda表达式)

1.类代码及作用:格式转化

public class ProtocalObj {
    /**
     * 生成xml
     *
     * @return
     */
    public String toXML() {
        XStream x = new XStream();
        // 设置别名,默认是类的全路径名
        x.alias(getClass().getSimpleName(), getClass());
        String xml = x.toXML(this);// 将本类转换成xml返回
        return xml;

    }

    /**
     * xml-->实体类
     *
     * @param xml
     * @return
     */
    public Object fromXML(String xml) {
        XStream x = new XStream();
        x.alias(getClass().getSimpleName(), getClass());
        return x.fromXML(xml);

    }
}

2.类代码及作用:继承格式转化类,实现Serializable接口,客户端服务端数据交互类

public class Message extends ProtocalObj implements Serializable {
    private static final long serialVersionUID = 1L;
    private String content;
    private int type;
    private long fileLength;
    private String fileName;

    public Message(int type, long fileLength, String fileName) {
        this.type = type;
        this.fileLength = fileLength;
        this.fileName = fileName;
    }


    public Message(String content, int type) {
        this.content = content;
        this.type = type;
    }

    public Message() {
    }
    public Message(int type) {
        this.type = type;
    }

    public String getContent() {
        return this.content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    @Override
    public String toXML() {
        return super.toXML();
    }

    @Override
    public Object fromXML(String xml) {
        return super.fromXML(xml);
    }

    public int getType() {
        return this.type;
    }

    public void setType(int type) {
        this.type = type;
    }

    public long getFileLength() {
        return fileLength;
    }

    public void setFileLength(long fileLength) {
        this.fileLength = fileLength;
    }

    public String getFileName() {
        return fileName;
    }

    public void setFileName(String fileName) {
        this.fileName = fileName;
    }
}

3.类代码及作用:

//信息类型类,用来表示信息类型的类
public class MessageType {
        public static final int MSG_TYPE_CHAT= 604;
        public static final int MES_TYPE_FILE = 800;
        public MessageType() {
        }

}

4.类代码及作用:服务端启动类

public class Server {
    //    程序入口类
//    public static ClientManager manager = new ClientManager();
    //服务器程序入口方法
    public static void main(String[] args) {
        try {
            ServerSocket server = new ServerSocket(9999);
            System.out.println("服务器启动");
//用死循环不断接受客户端
            while(true) {
                Socket client = server.accept();
                (new Thread(new ClientHandler(client))).start();
            }
        } catch (IOException var3) {
            var3.printStackTrace();
        }
    }

}

5.类代码及作用:服务端处理类

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
//服务端处理线程
public class ClientHandler implements Runnable {
    private Socket client;
    private DataOutputStream out;
    private DataInputStream in;

    //构造方法接受一个socket
    public ClientHandler(Socket client) {
        this.client = client;
        try {
            this.in = new DataInputStream(client.getInputStream());
            this.out = new DataOutputStream(client.getOutputStream());
        } catch (IOException var3) {
            var3.printStackTrace();
        }

    }

    //处理用户传来的消息,判断消息类型执行相应操作
    public void run() {
        try {
            String xml = null;
            Message message = null;
//            阻塞读取客户端信息
            while (true) {
                while ((xml = this.in.readUTF()) != null) {
                    message = new Message();
                    message = (Message) message.fromXML(xml);
                    System.out.println(message.toXML());
                    switch (message.getType()){
//                        聊天
                        case MessageType.MSG_TYPE_CHAT:
                            reply(message);
                            break;
//                            文件传输
                            case MessageType.MES_TYPE_FILE:
                                new Thread(new FileReceive(message.getFileName(),message.getFileLength())).start();

                    }
                }
            }
        } catch (IOException var6) {
            var6.printStackTrace();
        }

    }

    //返回给对应客户端
    public void reply(Message message) {
        try {
            System.out.println("客户端说:"+message.getContent());
            this.out.writeUTF(message.toXML());
            System.out.println("服务端说:"+message.getContent());
            this.out.flush();
        } catch (IOException var3) {
            var3.printStackTrace();
        }
    }
//    文件接收线程,新建ServerSocket,监听指定接口10000;接受客户端信息
    class FileReceive implements Runnable{
        private ServerSocket serverSocket;
        private Socket socket;
        private DataInputStream in;
        private String fileName;
        private long fileLength;
        public FileReceive( String fileName, long fileLength) {
            try {
                serverSocket=new ServerSocket(10000);
                socket=serverSocket.accept();
                in=new DataInputStream(socket.getInputStream());
            } catch (IOException e) {
                e.printStackTrace();
            }
            this.fileName = fileName;
            this.fileLength = fileLength;
        }
        @Override
        public void run() {
            try {
                FileOutputStream out=new FileOutputStream(new File("D:\\"+fileName));
                byte[] bytes=new byte[1024*1024];
                while (in.read(bytes)!=-1){
                    out.write(bytes);
                    out.flush();
                    System.out.println("文件传输完毕!");
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}


6.类代码及作用

import java.io.*;
import java.net.Socket;
import java.util.Scanner;

public class client {
    private static String content;
    private static Socket socket;
    private static DataOutputStream out;
    private static DataInputStream in;
    public static void main(String[] args) throws IOException {
        socket = new Socket("localhost", 9999);
        Scanner scanner = new Scanner(System.in);
//        键盘监听控制台输入内容
        while (keyBoardListener(scanner)) {
            new Thread(new Listener(socket)).start();
        }
    }

    //    键盘监听
    private static boolean keyBoardListener(Scanner scanner) {
        if (scanner.hasNext()) {
            content = scanner.next();
            if (content.equals("exit")) {
                System.out.print("程序退出");
                return false;
            } else {
//                判断输入内容
                if (content.startsWith("mess:")) {
                    String s=content.substring(5);
                    Message message = new Message(s, MessageType.MSG_TYPE_CHAT);
//                向服务端发送信息
                    System.out.println("信息---->");
                    send(message);
                } else if (content.startsWith("file:")) {
//                截取第五位开始的字符
                    File file=new File(content.substring(5));
                    Message message = new Message( MessageType.MES_TYPE_FILE,file.length(),file.getName());
                    send(message);
                    send(file);
                } else {
                    System.out.println("请输入正确格式!mess: or file: 内容或者文件地址!");
                }
                System.out.println("您输入:" + content);
                return true;
            }
        }
        return true;
    }

    //    发送信息
    private static void send(Message message) {
            try {
                out = new DataOutputStream(socket.getOutputStream());
                out.writeUTF(message.toXML());
                out.flush();
            } catch (IOException e) {
                e.printStackTrace();
            }
    }

    //    多线程发送文件
    private static void send(File file) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                byte[] bytes = new byte[1024];

                try {
                    Socket socket=new Socket("localhost",10000);
                    FileInputStream inputStream = new FileInputStream(file);
                    DataOutputStream out = new DataOutputStream(socket.getOutputStream());
                    while (inputStream.read(bytes) != -1) {
                        out.write(bytes);
                    }
                    inputStream.close();
                    out.flush();
//                out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();

    }
//多线程,监听服务端返回消息
    static class Listener implements Runnable {
        private Socket socket;
        private DataInputStream in;

        public Listener(Socket socket) {
            this.socket = socket;
            try {
                in = new DataInputStream(socket.getInputStream());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void run() {
            String xml = null;
            Message message = new Message();
            while (true) {
                    try {
                        while ((xml=in.readUTF())!=null){
                            message=(Message)message.fromXML(xml);
                            switch (message.getType()){
                                case MessageType.MSG_TYPE_CHAT:
                                    System.out.println("服务端说:"+message.getContent());
                                    break;
                                    case MessageType.MES_TYPE_FILE:
                                        System.out.println("发送成功!");
                                        break;
                                }
                            }


                        } catch (IOException e) {
                        e.printStackTrace();
                    }
            }
        }
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值