Socket在Android中的用法

来源:互联网 发布:魏强斌 知乎 编辑:程序博客网 时间:2024/06/06 06:35

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
原创粉丝点击