zoukankan      html  css  js  c++  java
  • JAVA网络编程

    学习资料:《java疯狂讲义》

    网络已经像空气和水一样,成为了人们日常生活离不开的东西。网络也是开发中不可或缺的知识。我们学习理论很重要,将理论运用于实践更能加强对理论的理解,最后软件开发的生产力也将随之提高。

    在学校里学的那本《计算机网络》,已经忘得差不多了。。。。

    1.网络基础

    网络模型:

    ip(地址):唯一标识网络中的一个通信实体(主机、打印机、路由器端口等等)

    TCP:Transmission Control Protocol,传输层协议。

    端口(房间号):一个通信实体可以有多个通信程序同时提供网络服务,每一个通信服务占用一个端口。

    URL(locators):代表互联网里的统一资源定位器。可以指向文件、目录、或是更为复杂的对象引用,如数据库或搜索引擎的查询。URL格式如下:

    protocol://host:port/resourceName

    URI(identifiers):Java的URI不能用于定位任何资源,它的唯一作用就是解析。

    TCP/IP网络模型: TCP和IP协议互补,结合使用。原理是在网络两端分别建立socket通信端口,实现虚拟链路,并通过产生的IO通信。

    2.java的基本网络支持

    java.net包【可以对照API学习】:http://tool.oschina.net/apidocs/apidoc?api=jdk_7u4

    InetAddress类代表ip地址(没有加入端口): 它并没有提供太多的方法,但是该类是网络通信的基础,经常被大量使用。

    public class InetAddressTest {
        public static void main(String[] args) throws IOException
        {
            InetAddress ip =InetAddress.getByName("www.crazyit.org");
            System.out.println(ip.isReachable(2000));
            System.out.println(ip.getHostName());
            System.out.println(ip.getHostAddress());
            InetAddress local=InetAddress.getLocalHost();
            System.out.println(local);
            System.out.println(local.getHostAddress());
        }
    
    }
    View Code

    URLEncoder和URLDecoder类:用于完成非西欧字符串(如中文)字符串和application/x-www-form-urlencoded MIME字符串之间的转换。

    如:中国<----->%E4%B8%AD%E5%9B%BD (不同编码方式GBK,utf-8,转换结果不一样)

    public class URLDecoderTest {
    
        public static void main(String[] args) throws UnsupportedEncodingException {
            // TODO Auto-generated method stub
            String keyWord=URLDecoder.decode("%E4%B8%AD%E5%9B%BD","utf-8");
            System.out.println(keyWord);
            String urlStr = URLEncoder.encode("中国", "GBK");
            System.out.println(urlStr);
        }
    View Code

    输出结果:

    中国
    %D6%D0%B9%FA

    URL、URLConnection和URLPermission类:

    例1:实现一个简单的多线程下载工具类

    从 http://www.crazyit.org/ 下载一个名为"ios.png”的图片。

    /*实现一个多线程下载工具类*/
    public class DownUtil {
        private String path;
        private String targetFile;
        private int threadNum;
        private DownThread[] threads;
        private int fileSize;
        
        public DownUtil(String path, String targetFile, int threadNum) {
            this.path = path;
            this.threadNum = threadNum;
            threads = new DownThread[threadNum];//这里没有初始化的话会报错NULL POINTER
            this.targetFile = targetFile;
            
        }
    
        public void download() throws Exception
        {
            URL url = new URL(path);
            HttpURLConnection conn =(HttpURLConnection) url.openConnection();
            conn.setConnectTimeout(5*1000);
            conn.setRequestMethod("GET");
            conn.setRequestProperty("Accept","image/gif, image/jpeg, image/pjpeg, image/pjpeg, "
                    +"application/x-shockwave-flash, application/xaml+xaml, "
                    +"application/vnd.ms-xpsdocument, application/x-ms-xbap, "
                    +"application/x-ms-application, application/vnd.ms-excel, "
                    +"application/vnd.ms-powerpoint, application/msword, */*");
            conn.setRequestProperty("Accept-Language",  "zh-CN");
            conn.setRequestProperty("Charset", "UTF-8");
            conn.setRequestProperty("Connection", "Keep-Alive");
            
            //得到文件大小
            fileSize=conn.getContentLength();
            conn.disconnect();
            int currentPartSize=fileSize/threadNum+1;
            RandomAccessFile file=new RandomAccessFile(targetFile,"rw");
            System.out.println(file.toString());
            //设置本地文件大小
            file.setLength(fileSize);
            file.close();
            for(int i =0;i<threadNum;i++)
            {
                //计算每个线程下载的开始位置
                int startPos=i*currentPartSize;
                //每个线程使用一个RandomAccessFile进行下载
                RandomAccessFile currentPart=new RandomAccessFile(targetFile,"rw");
                //定义该线程的下载位置
                currentPart.seek(startPos);
                threads[i] = new DownThread(startPos,currentPartSize,currentPart);
                //启动下载线程
                threads[i].start();
                
            }
            
        }
        
        public double getCompleteRate()
        {
            int sumSize=0;
            for(int i=0;i<threadNum;i++)
            {
                sumSize+=threads[i].length;
            }
            return sumSize*1.0/fileSize;
        }
        private class DownThread extends Thread{
            //当前线程的下载位置
            private int startPos;
            //当前线程负责下载的文件大小
            private int currentPartSize;
            //当前线程需要下载的文件块
            //该线程已下载的字节数
            public int length;
            private RandomAccessFile currentPart;//RandomAccessFile类
            public DownThread(int startPos, int currentPartSize, RandomAccessFile currentPart) {
                super();
                this.startPos = startPos;
                this.currentPartSize = currentPartSize;
                this.currentPart = currentPart;
            }
            public void run()
            {
                try
                {
                    URL url = new URL(path);
                    HttpURLConnection conn =(HttpURLConnection) url.openConnection();
                    conn.setConnectTimeout(5*1000);
                    conn.setRequestMethod("GET");
                    conn.setRequestProperty("Accept","image/gif, image/jpeg, image/pjpeg, image/pjpeg, "
                            +"application/x-shockwave-flash, application/xaml+xaml, "
                            +"application/vnd.ms-xpsdocument, application/x-ms-xbap, "
                            +"application/x-ms-application, application/vnd.ms-excel, "
                            +"application/vnd.ms-powerpoint, application/msword, */*");
                    conn.setRequestProperty("Accept-Language",  "zh-CN");
                    conn.setRequestProperty("Charset", "UTF-8");
                    
                    InputStream inStream=conn.getInputStream();
                    //跳过startPos个字符,表示该线程只下载自己负责的那部分文件
                    inStream.skip(this.startPos);
                    byte[] buffer = new byte[1024];
                    int hasRead=0;
                    //读取网络数据,并写入本地文件
                    while(length<currentPartSize && (hasRead=inStream.read(buffer))!=-1)
                    {
                        currentPart.write(buffer, 0, hasRead);
                        length+=hasRead;
                    }
                    currentPart.close();
                    inStream.close();
                    
                }
                catch(Exception e)
                {
                    e.printStackTrace();
                }
            }        
        }
    }
    View Code

    测试下载工具类

    /*测试下载工具类*/
    public class MultiThreadDown {
        public static void main(String[] args) throws Exception
        {
            final DownUtil downUtil = new DownUtil("http://www.crazyit.org/"
                    +"attachments/month_1403/1403202355ff6cc9a4fbf6f14a.png","ios.png",5);
            downUtil.download();
            new Thread(() ->{
                while(downUtil.getCompleteRate()<1)
                {
                    System.out.println("已完成:"+downUtil.getCompleteRate());
                    try
                    {
                        Thread.sleep(1000);
                    }
                    catch(Exception ex){}
                }
            }).start();
        }
    
    }
    View Code

    关于断点下载,加一个配置文件,该配置文件分别记录每个线程已经下载到哪个字节,当断开网络后再次开始下载时,每个线程根据配置文件里记录的位置向后下载即可。

    例2:向Web站点发送GET请求、POST请求,并从Web站点取得响应。

    public class GetPostTest {
    
        public static void main(String[] args) {
            // TODO Auto-generated method stub
            String s =GetPostTest.sentGet("http://localhost:8080/index.jsp", null);
            System.out.println(s);
            String s1=GetPostTest.sendPost("http://localhost:8080/abc/login.jsp", "name=crazyit.org&pass=leegang");
            System.out.println(s1);
    
        }
    /*向指定URL发送GET方式的请求
    @param url
    @param param 请求参数name1=value2&name2=value2的形式
    @return URL 远程资源的响应
    */
        public static String sentGet(String url,String param)
        {
            String result="";
            String urlName=url+"?"+param;
            try
            {
                URL realUrl=new URL(urlName);
                URLConnection conn=realUrl.openConnection();
                conn.setRequestProperty("accept", "*/*");
                conn.setRequestProperty("connection", "Keep-Alive");
                conn.setRequestProperty("user-agent", "Mozilla/4.0(compatible; MSIE 6Map<K, V> Windows NT 5.1; SV1)");
                conn.connect();
                Map<String, List<String>> map=conn.getHeaderFields();
                for(String key:map.keySet())
                {
                    System.out.println(key+"-->"+map.get(key));
                }
                try
                (
                    //定义bufferedReaders输入流来读取URL的响应
                    BufferedReader in = new BufferedReader(
                            new InputStreamReader(conn.getInputStream(),"utf-8")))
                {
                    String line;
                    while((line=in.readLine())!=null)
                    {
                        result+="
    "+line;
                    }
                    
                }
                
            }
            catch(Exception e)
            {
                System.out.println("发送GET请求出现异常!  "+e);
                e.printStackTrace();
            }
            return result;
        }
    /*    向指定URL发送POST方式的请求
        @param url 
        @param param
        @return URL
        */
        public static String sendPost(String url, String param)
        {
            String result="";
            try
            {
                URL realUrl = new URL(url);
                URLConnection conn= realUrl.openConnection();
                conn.setRequestProperty("accept", "*/*");
                conn.setRequestProperty("connection", "Keep-Alive");
                conn.setRequestProperty("user-agent", "Mozilla/4.0(compatible; MSIE 6Map<K, V> Windows NT 5.1; SV1)");
                //发送post请求必须设置如下两行
                conn.setDoOutput(true);
                conn.setDoInput(true);
                try
                (
                    PrintWriter out = new PrintWriter(conn.getOutputStream()))
                {
                    out.print(param);
                    //flush输出流的缓冲
                    out.flush();
                }
                try
                (
                    //定义bufferedReaders输入流来读取URL的响应
                    BufferedReader in = new BufferedReader(
                            new InputStreamReader(conn.getInputStream(),"utf-8")))
                {
                    String line;
                    while((line=in.readLine())!=null)
                    {
                        result+="
    "+line;
                    }
                    
                }
            }
                catch(Exception e)
                {
                    System.out.println("发送GET请求出现异常!  "+e);
                    e.printStackTrace();
                }
                return result;
            }
    }
    
            
    View Code

    暴力破解:不停变换用户名和密码提交给登录站点,直至返回成功。

    Socket、ServerSocket类

    例子:实现一个简单的socket通信

    public class Server {
        public static void main(String[] args) throws IOException
        {
        ServerSocket ss = new ServerSocket(30000);
        while(true)
        {
            Socket s =ss.accept();
            PrintStream ps= new PrintStream(s.getOutputStream());
            ps.println("新年快乐!");
            ps.close();
            s.close();
        }
        }
    }
    View Code
    public class Client {
    
        public static void main(String[] args) throws UnknownHostException, IOException {
            // TODO Auto-generated method stub
            Socket socket=new Socket("127.0.0.1",30000);
            BufferedReader br = new BufferedReader(
                    new InputStreamReader(socket.getInputStream()));
            String line=br.readLine();
            System.out.println(line);
            br.close();
            socket.close();
    
        }
    
    }
    View Code

    加入多线程:每个客户通过键盘键入一些内容后按回车键,即可在控制台上收到刚刚输入的内容,粗略地实现了一个C/S结构的聊天室的功能。

    public class MyServer {
        //定义保存所有socket的arraylist,并将其包装为线程安全的
        public static List<Socket> socketList =Collections.synchronizedList(new ArrayList<>());
        public static void main(String[] args) throws IOException
        {
            ServerSocket ss= new ServerSocket(30001);
            while(true)
            {
                //此代码会阻塞,一直等待别人的连接
                Socket s =ss.accept();
                socketList.add(s);
                //每当客户端连接后启动一个serverThread线程为该客户端服务
                new Thread(new ServerThread(s)).start();
                
            }
        }
        
    
    }
    View Code
    public class ServerThread implements Runnable{
        Socket s =null;
        BufferedReader br = null;
        public ServerThread(Socket s) throws IOException
        {
            this.s=s;
            br = new BufferedReader(new InputStreamReader(s.getInputStream()));
            
        }
        public void run()
        {
            try
            {
                String content =null;
                while((content=readFromClient())!=null)
                {
                    //遍历socket,将读到的内容向每个socket发一次
                    for(Socket s:MyServer.socketList)
                    {
                        PrintStream ps = new PrintStream(s.getOutputStream());
                        ps.println(content);
                    }
                }
            }
            catch(IOException e)
            {
                e.printStackTrace();
            }
        }
        private String readFromClient()
        {
            try
            {
                return br.readLine();
            }
            catch(IOException e)
            {
                MyServer.socketList.remove(s);
            }
            return null;
        }
    
    }
    View Code
    public class MyClient {
    
        public static void main(String[] args) throws UnknownHostException, IOException {
            // TODO Auto-generated method stub
            Socket s = new Socket("127.0.0.1",30001);
            new Thread(new ClientThread(s)).start();
            PrintStream ps = new PrintStream(s.getOutputStream());
            String line=null;
            BufferedReader br = new BufferedReader(
                    new InputStreamReader(System.in));
            while((line=br.readLine())!=null)
            {
                ps.println(line);
            }
    
        }
    
    }
    View Code
    public class ClientThread implements Runnable{
        private Socket s;
        BufferedReader br =null;
        public ClientThread(Socket s) throws IOException
        {
            this.s=s;
            br = new BufferedReader(new InputStreamReader(s.getInputStream()));
            
        }
    public void run()
    {
        try
        {
            String content=null;
            while((content=br.readLine())!=null)
            {
                System.out.println(content);
            }
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }
    }
    
    }
    View Code

    记录用户(客户端)信息,实现私聊功能

    <!----未完待续----!>

  • 相关阅读:
    关于在配置mysql的时候,总是在最后一步startservice的时候未响应出错
    html标签默认属性值之margin;padding值
    一个误区(关于javascript的字符串拼接)
    简单实用的下拉级联菜单
    js淡入淡出效果框架
    js多物体运动框架
    26 个 jQuery使用技巧(转载)
    js自定义滚动条完美兼容ff,IE
    CSS中单位px和em的区别解析
    js仿flash图片展示控件
  • 原文地址:https://www.cnblogs.com/flyingbee6/p/5136544.html
Copyright © 2011-2022 走看看