Socket在Android中的用法

Socket的简介

网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket。

在Android中我们常用的Socket形式为一方是客户端一方是服务端,分别具有数据的发送与接受的功能
在客户端使用Soket时,首先应了解服务端的Ip地址(只有知道,才能找到服务器)并知道服务器所监听
的端口号,才能顺利的建立连接

在服务端使用Socket时,应首先规定出需要监听的端口号,以便准确监听。

客户端Soket的简单用法

 public class MsgClient {
        public DataOutputStream outs;

        public static void main(String[] args) {
            try {
                MsgClient client = new MsgClient();
                client.connServer("127.0.0.1", 9090);
            } catch (UnknownHostException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        public void sendTextMsg(DataOutputStream out, String msg) throws IOException {
            byte[] bytes = msg.getBytes();
            out.write(bytes);
            out.flush();
        }

        public void connServer(String ip, int port) throws UnknownHostException, IOException {
            Socket client = new Socket(ip, port);
            InputStream in = client.getInputStream();
            OutputStream out = client.getOutputStream();
            outs = new DataOutputStream(out);
            sendTextMsg(outs, "我发送啦");
        }
    }

Socket客户端的用法比较简单,如上述一样,指定客户端Ip和监听端口,然后在连接成功后,就能够通过获取相应的流来进行数据的发送与接收操作

Socket服务端

 public static void main(String[] args) {
        try {
            MsgServer server = new MsgServer();
            server.setUpServer(9090);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void setUpServer(int port) throws IOException {
        ServerSocket server = new ServerSocket(port);
        while(true) {
            Socket client = server.accept();//阻塞状态,生成
            System.out.println("客户端IP:"+client.getRemoteSocketAddress());
            processMesage(client);
        }
    }

    private void processMesage(Socket client) throws IOException {
        InputStream ins = client.getInputStream();
        DataInputStream dins = new DataInputStream(ins);
        //服务端接收数据
        while(true) { 
            String msg = dins.readLine();
            System.out.println("发来的内容是:"+msg);
        }
    }

服务器的原理也和客户端相似,通过指定对应的Port来监听客户端的连接,当 server.accept(); 的时候处于阻塞状态等待客户端的连接,当客户端连接时生成Socket实例,针对新的socket对象可进行相关操作

Socket心跳包

在使用过程中,由于客户端和服务端的机制原因,客户端和服务器端无法准确的了解对方是否还存在,所以心跳包也就此出现,基本原理就是客户端定时向服务端报告自己在线,服务端进行接收信息了解客户端在线,并会送客户端信息,具体代码如下

public class Server {

    /**
     * 要处理客户端发来的对象,并返回一个对象,可实现该接口。
     */
    public interface ObjectAction{
        Object doAction(Object rev);
    }

    public static final class DefaultObjectAction implements ObjectAction{
        public Object doAction(Object rev) {
            System.out.println("处理并返回:"+rev);
            return rev;
        }
    }

    public static void main(String[] args) {
        int port = 65432;
        Server server = new Server(port);
        server.start();
    }

    private int port;
    private volatile boolean running=false;
    private long receiveTimeDelay=3000;
    private ConcurrentHashMap<Class, ObjectAction> actionMapping = new ConcurrentHashMap<Class,ObjectAction>();
    private Thread connWatchDog;

    public Server(int port) {
        this.port = port;
    }

    public void start(){
        if(running)return;
        running=true;
        connWatchDog = new Thread(new ConnWatchDog());
        connWatchDog.start();
    }

    @SuppressWarnings("deprecation")
    public void stop(){
        if(running)running=false;
        if(connWatchDog!=null)connWatchDog.stop();
    }

    public void addActionMap(Class<Object> cls,ObjectAction action){
        actionMapping.put(cls, action);
    }

    class ConnWatchDog implements Runnable{
        public void run(){
            try {
                ServerSocket ss = new ServerSocket(port,5);
                while(running){
                    Socket s = ss.accept();
                    new Thread(new SocketAction(s)).start();
                }
            } catch (IOException e) {
                e.printStackTrace();
                Server.this.stop();
            }

        }
    }

    class SocketAction implements Runnable{
        Socket s;
        boolean run=true;
        //逻辑问题,上次接收时间默认应为0
        long lastReceiveTime = System.currentTimeMillis();
//        long lastReceiveTime = 0;
        public SocketAction(Socket s) {
            this.s = s;
        }
        public void run() {
            while(running && run){
                if(System.currentTimeMillis()-lastReceiveTime>receiveTimeDelay){
                    System.out.println("我进来了");
                    overThis();
                }else{
                    try {
                        InputStream in = s.getInputStream();
                        if(in.available()>0){
                            ObjectInputStream ois = new ObjectInputStream(in);
                            Object obj = ois.readObject();
                            lastReceiveTime = System.currentTimeMillis();
                            System.out.println("接收:\t"+obj);
                            ObjectAction oa = actionMapping.get(obj.getClass());
                            oa = oa==null?new DefaultObjectAction():oa;
                            Object out = oa.doAction(obj);
                            if(out!=null){
                                ObjectOutputStream oos = new ObjectOutputStream(s.getOutputStream());
                                oos.writeObject(out);
                                oos.flush();
                            }
                        }else{
                            Thread.sleep(10);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                        overThis();
                    }
                }
            }
        }

        private void overThis() {
            if(run)run=false;
            if(s!=null){
                try {
                    s.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("关闭:"+s.getRemoteSocketAddress());
            System.out.println("断开连接");
        }
    }
}
public class Client {

    /**
     * 处理服务端发回的对象,可实现该接口。
     */
    public static interface ObjectAction{
        void doAction(Object obj,Client client);
    }

    public static final class DefaultObjectAction implements ObjectAction{
        public void doAction(Object obj,Client client) {

            System.out.println("处理:\t"+obj.toString());
        }
    }

    public static void main(String[] args) throws UnknownHostException, IOException {
        String serverIp = "127.0.0.1";
        int port = 65432;
        Client client = new Client(serverIp,port);
        client.start();
    }

    private String serverIp;
    private int port;
    private Socket socket;
    private boolean running=false;
    private long lastSendTime;
    private ConcurrentHashMap<Class, ObjectAction> actionMapping = new ConcurrentHashMap<Class,ObjectAction>();

    public Client(String serverIp, int port) {
        this.serverIp=serverIp;this.port=port;
    }

    public void start(){
        if(running)return;
        try {
            socket = new Socket(serverIp,port);
            System.out.println("本地端口:"+socket.getLocalPort());
            lastSendTime=System.currentTimeMillis();
            running=true;
            new Thread(new KeepAliveWatchDog()).start();
            new Thread(new ReceiveWatchDog()).start();

        } catch (IOException e) {
            System.out.println("u发发");
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e1) {
                e1.printStackTrace();
            }
            System.out.println(port+"");
            Client client = new Client(serverIp,port);
            client.start();
            e.printStackTrace();
        }
    }

    public void stop(){
        if(running)running=false;
        System.out.println("Client stop");
    }

    /**
     * 添加接收对象的处理对象。
     * @param cls 待处理的对象,其所属的类。
     * @param action 处理过程对象。
     */
    public void addActionMap(Class<Object> cls,ObjectAction action){
        actionMapping.put(cls, action);
    }

    public void sendObject(Object obj) {
        try {
            ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
            oos.writeObject(obj);
            System.out.println("发送:\t"+obj);
            oos.flush();
        } catch (IOException e) {
            System.out.println("尼玛炸了");
            stop();
            start();
            e.printStackTrace();
        }

    }

    class SendMessage implements Runnable {
        @Override
        public void run() {
            while (true) {
                Scanner scanner = new Scanner(System.in);
                String s = scanner.nextLine();

            }
        }
    }


    class KeepAliveWatchDog implements Runnable{
        long checkDelay = 10;
        long keepAliveDelay = 2000;
        public void run() {
            while(running){
                if(System.currentTimeMillis()-lastSendTime>keepAliveDelay){
                    Client.this.sendObject(new KeepAlive());
                    lastSendTime = System.currentTimeMillis();
                }else{
                    try {
                        Thread.sleep(checkDelay);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                        Client.this.stop();
                    }
                }
            }
        }
    }

    class ReceiveWatchDog implements Runnable{
        public void run() {
            while(running){
                try {
                    InputStream in = socket.getInputStream();
                    if(in.available()>0){
                        ObjectInputStream ois = new ObjectInputStream(in);
                        Object obj = ois.readObject();
                        System.out.println("接收:\t"+obj);
                        ObjectAction oa = actionMapping.get(obj.getClass());
                        oa = oa==null?new DefaultObjectAction():oa;
                        oa.doAction(obj, Client.this);
                    }else{
                        Thread.sleep(10);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    Client.this.stop();
                }
            }
        }
    }

}
public class KeepAlive implements Serializable {

    private static final long serialVersionUID = -2813120366138988480L;

    /* 覆盖该方法,仅用于测试使用。
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())+"\t维持连接包";
    }

}

Socket中传输文件(并能传递文件名)

/**
 * Created by admin on 2016/9/20/0020.
 *
 * 客户端给服务端发送文件夹
 */
public class TCPServer {
    static int size=10*1024;
    static byte[] buf=new byte[size];
    static int len=-1;
    public static void main(String[] args) throws Exception{
        ServerSocket ss=null;
        OutputStream out=null;
        Socket s=null;
        try {
            ss=new ServerSocket(9987);
            System.out.println("等待客户端连接");
            s=ss.accept();
            System.out.println("连接成功");
//          InputStream in=s.getInputStream();
            out=s.getOutputStream();

            long start=System.currentTimeMillis();
            System.out.println("开始发送文件");
            String fileName="D:\\新建文件夹\\demo1";//"I:"+File.separator;
            if(!fileName.endsWith(File.separator)){
                fileName+=File.separator;
            }
            File file=new File(fileName);
            String parent=file.getParent();
            if(parent==null){
                File[] fs=file.listFiles();
                for(int i=0;i<fs.length;i++){
                    if(fs[i].isHidden())
                    {
                        System.out.println("隐藏文件"+fs[i].getAbsolutePath()+",不会被发送");
                        continue;
                    }
                    test(fs[i],out,fs[i].getParent());
                }
            }else{
                test(file,out,parent);
            }
            System.out.println("文件发送成功"+(System.currentTimeMillis()-start)+"ms");
          out.write("接受成功".getBytes());
            out.flush();
        } finally {
            if(out!=null)out.close();
            if(s!=null)s.close();
            if(ss!=null)ss.close();
        }
    }

    private static void test(File file,OutputStream out,String sendFileName)throws Exception{
        FileInputStream in=null;
        String fname=file.getAbsolutePath();
        String name=fname.replace(sendFileName, "");
        if(file.isDirectory()){
            File[] fs=file.listFiles();
            out.write(new byte[]{(byte)2}, 0, 1);//2:文件夹名
            int fileLength=name.getBytes().length;
            out.write(intToBytes(fileLength),0,4);//文件名的长度
            out.write(name.getBytes(),0,name.getBytes().length);//文件名
            System.out.println("文件夹:"+name+"   "+name.length());
            out.flush();
            for(int i=0;i<fs.length;i++){
                if(fs[i].isHidden())
                {
                    System.out.println("隐藏文件"+fs[i].getAbsolutePath()+",不会被发送");
                    continue;
                }
                test(fs[i],out,sendFileName);
            }
        }else{
            out.write(new byte[]{(byte)1}, 0, 1);//1:文件名
            int fileLength=name.getBytes().length;
            out.write(intToBytes(fileLength),0,4);//文件夹名的长度
            out.write(name.getBytes(),0,name.getBytes().length);//文件夹名
            System.out.println("文件:"+name+"   "+name.length()+"  "+file.length());
            out.flush();
            in=new FileInputStream(file);
            out.write(new byte[]{(byte)0}, 0, 1);//0表示文件数据
            out.write(longToBytes(file.length()),0,8);//文件的长度
            out.flush();
            while((len=in.read(buf,0,size))!=-1){
                out.write(buf,0,len);
                out.flush();
            }
            in.close();
        }
    }

    private static byte[] intToBytes(int i){
        byte[] b=new byte[4];
        b[0]=(byte)((i>>>24)&255);
        b[1]=(byte)((i>>>16)&255);
        b[2]=(byte)((i>>>8)&255);
        b[3]=(byte)(i&255);
        return b;
    }

    private static byte[] longToBytes(long i){
        byte[] b=new byte[8];
        b[0]=(byte)((i>>>56)&255);
        b[1]=(byte)((i>>>48)&255);
        b[2]=(byte)((i>>>40)&255);
        b[3]=(byte)((i>>>32)&255);
        b[4]=(byte)((i>>>24)&255);
        b[5]=(byte)((i>>>16)&255);
        b[6]=(byte)((i>>>8)&255);
        b[7]=(byte)(i&255);
        return b;
    }
}
public class TCPClient {
    public static void main(String[] args) throws Exception{
        System.setOut(new PrintStream(new FileOutputStream("D:\\log.txt")));
        Socket s=null;
        InputStream in=null;
        try {
            s=new Socket("127.0.0.1", 9987);
            String savePath="D:\\新建文件夹\\demo2";//"D:"+File.separator+"test"+File.separator;
            in=s.getInputStream();
            int size=10*1024;
            byte[] buf=new byte[size];
            int len=-1;
            byte[] bs=new byte[size];
            while((len=in.read(buf, 0, size))!=-1){
                writeData(buf,0,len,savePath,bs);
            }

            if(out!=null){
                out.flush();
                out.close();
            }
        } finally {
            if(in!=null)
                in.close();
            if(s!=null)
                s.close();
        }
    }

    static FileOutputStream out=null;
    static long count=0;//计算是否完成数据的读取,开始下一条命令
    static int cmd=-1;

    static int bsl=0;
    private static void writeData(byte[] buf,int off, int len,String savePath,byte[] bs) throws Exception{
        if(len-off==0)return;
        System.out.println("偏移量:"+off+"命令"+cmd+"数量:"+count);
        int i=off;
        if(count==0l){//如果一条命令的数据已经读完就开始读取下一条命令
            cmd=buf[i++];
            System.out.println("获取命令:"+cmd);
            count=-1l;
            if(len-i==0)return;
            writeData(buf,i,len,savePath,bs);
        }else if(count==-1l){//读取文件(夹)名称的长度或文件的大小
            System.out.println("获取长度");
            switch (cmd){
                case 0:
                    if(len-i+bsl<8){
                        System.arraycopy(buf, i, bs, bsl, len-i);
                        System.out.println("读取长度1:"+(len-i)+"  未读取完");
                        bsl=len-i;
                        i=0;
                        return;
                    }
                    System.arraycopy(buf, i, bs, bsl, 8-bsl);
                    System.out.println("读取长度1:"+(8-bsl)+"  读取完");
                    count=bytesToLong(bs, 0);
                    i+=8-bsl;
                    bsl=0;
                    writeData(buf,i,len,savePath,bs);
                    break;
                case 1:
                case 2:
                    if(len-i+bsl<4){
                        System.arraycopy(buf, i, bs, bsl, len-i);
                        System.out.println("读取长度2:"+(len-i)+"  未读取完");
                        bsl=len-i;
                        i=0;
                        return;
                    }
                    System.arraycopy(buf, i, bs, bsl, 4-bsl);
                    System.out.println("读取长度2:"+(4-bsl)+"  读取完");
                    count=bytesToInt(bs, 0);
                    i+=4-bsl;
                    bsl=0;
                    writeData(buf,i,len,savePath,bs);
                    break;
            }
        }else{//写入文件或创建文件夹、创建文件输出流
            System.out.println("3");
            switch (cmd){
                case 0:
                    System.out.println("写入文件");
                    if(len-i-count>0){
                        try{
                            System.out.println("写入文件      长度:"+count+"文件写入完成");
                            out.write(buf, i, (int)count);
                            i+=count;
                            count=0;
                            out.flush();
                        }finally{
                            if(out!=null)out.close();
                        }
                        writeData(buf,i,len,savePath,bs);
                    }else{
                        System.out.println("写入文件      长度:"+(len-i)+"文件写入没有完成");
                        out.write(buf,i,len-i);
                        count-=len-i;
                        i=0;
                    }break;
                case 1:
                    if(len-i-count<0){
                        System.out.println("获取文件名字:"+(len-i)+"写入没有完成    剩余长度"+count);
                        System.arraycopy(buf, i, bs, bsl, len-i);
                        bsl+=len-i;
                        count-=bsl;
                        i=0;
                        return;
                    }else{
                        System.out.println("获取文件名字:"+(count-bsl)+"写入完成    剩余长度");
                        System.arraycopy(buf, i, bs, bsl, (int)count);
                        String name=new String(bs,0,(int)count+bsl);
                        System.out.println("文件:"+savePath+name);
                        out=new FileOutputStream(savePath+name);
                        bsl=0;
                        i+=count;
                        count=0;
                        writeData(buf,i,len,savePath,bs);
                    }
                    break;
                case 2:
                    if(len-i-count<0){
                        System.out.println("获取文件夹名字:"+(len-i)+"写入没有完成    剩余长度"+count);
                        System.arraycopy(buf, i, bs, bsl, len-i);
                        bsl+=len-i;
                        count-=bsl;
                        i=0;
                        return;
                    }else{
                        System.out.println(len+"   "+count+"   "+bsl+"  ");
                        System.out.println("获取文件夹名字:"+(count-bsl)+"写入完成    剩余长度");
                        System.arraycopy(buf, i, bs, bsl, (int)count);
                        String name=new String(bs,0,bsl+(int)count);
                        File file=new File(savePath+name);
                        bsl=0;
                        i+=count;
                        count=0;
                        if(!file.exists()){
                            file.mkdirs();
                        }
                        System.out.println("文件夹:"+savePath+name);
                        writeData(buf,i,len,savePath,bs);
                    }
                    break;
            }
        }

    }

    private static int bytesToInt(byte[] buf,int off){
        int i=0;
        i=i|((buf[off]&255)<<24);
        i=i|((buf[off+1]&255)<<16);
        i=i|((buf[off+2]&255)<<8);
        i=i|(buf[off+3]&255);
        return i;
    }

    private static long bytesToLong(byte[] buf,int off){
        long i=0;
        i=i|(((long)buf[off]&255)<<56)
                |(((long)buf[off+1]&255)<<48)
                |(((long)buf[off+2]&255)<<40)
                |(((long)buf[off+3]&255)<<32)
                |(((long)buf[off+4]&255)<<24)
                |(((long)buf[off+5]&255)<<16)
                |(((long)buf[off+6]&255)<<8)
                |((long)buf[off+7]&255);
        return i;
    }
}

具体实现原理我也没看懂···(好尴尬),再次作为记录,如果小伙伴们知道,欢迎帮本宝宝指个明路。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值