zoukankan      html  css  js  c++  java
  • 黑马程序员

    网络模型:
    OSI参考模型 TCP/IP参考模型

    1.找到对方IP
    2.数据要发送到对方指定的应用程序上,为了标识这些应用程序,所以给这些网络应用程序都用数字进行标识。
    为了方便称呼这个数字,叫做端口,逻辑端口。
    3.定义通信规则。这个规则称为协议。国际通用协议 TCP/IP
    OSI参考模型 TCP/IP参考模型
    应用层
    表示层 应用层
    会话层
    传输层 传输层
    网络层 网际层
    数据链路层 主机至网络层
    物理层
    IP地址 :网络中设备的标识。不易记忆,可用主机名。
    端口:用于标识进程的逻辑地址,不同进程的标识
    有效端口 0~65535,其中0~1024系统使用或保留端口。
    以下代码简单演示获取IP地址方法

    import java.net.*;
    import java.io.*;
    class  IPDemo
    {
        public static void main(String[] args) throws Exception
        {
            InetAddress i = InetAddress.getLocalHost();             //获取本地IP地址
            System.out.println(i.toString());
            InetAddress ia = InetAddress.getByName("www.baidu.com");//获取百度的IP地址
            System.out.println("name:"+ia.getHostName());            //打印百度的主机名
            System.out.println("address:"+ia.getHostAddress());        //打印百度的主机地址
        }
    }

    UDP:将数据及源和目的封装成数据包中,不需要建立连接
    每个数据包大小限制在64k内
    因无连接,是不可靠协议
    不许建立连接,速度快
    TCP:建立连接,形成传输数据的通道
    在连接中进行大数据批量传输
    通过三次握手完成连接,是可靠协议
    必须建立连接,效率会稍低
    Socket:Socket就是为网络服务提供的一种机制。
    通信的两端都是有Socket。
    网络通信其实就是Socket间的通信。
    数据在连个Socket间通过IO传输。
    需求:通过UDP传输方式,将一段文字数据发送出去
    思路:
    1.建立UDPSocket服务
    2.提供数据,并将数据封装到数据包中。
    3.通过socket服务的发送功能,将数据包发出去。
    4.关闭资源。

    import java.io.*;
    import java.net.*;
    class UdpSend   //建立UDP的客户端
    {
        public static void main(String[] args) throws Exception
        {
            //1.创建udp服务,通过DatagramSocket对象
            DatagramSocket ds = new DatagramSocket ();
            //2.确定数据,并封装成数据包 
            byte[] buf = "udp ge men lai le ".getBytes(); //创建字节数组存储字符串的字节数据
            DatagramPacket dp =                              //将字节数组封装,并设置目的地为192.168.0.100的10000端口
                new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.0.100"),10000); 
            //3.铜鼓Socket服务,将已有的数据包发送出去,通过send方法发送出去
            ds.send(dp);
            //4.关闭资源
            ds.close();
        }
    }

    需求:定义一个应用程序,用于接收udp数据
    1.定义udpsocket服务。
    2.定义一个数据包,因为要存储接收到的字节数据。
    因为数据包对象中有更多功能可以提取字节数据的不同数据信息。
    3.通过socket服务的recevice方法将受到的数据存入到定义好的数据中
    4.通过数据包对象的特有功能,将这些不同的数据取出,打印在控制台上
    5.关闭资源

    import java.io.*;
    import java.net.*;
    class UdpReceive    //建立UDP的服务端
    {
        public static void main(String[] args) throws Exception
        {
            //1.创建udp socket,建立端点,设置端口为10000
            DatagramSocket ds = new DatagramSocket (10000);
            //2.确定数据,用于存储数据
            while(true)
            {
                byte[] buf = new byte [1024];    //建立字节数组
                DatagramPacket dp =                //将数据封装入字节数组中
                    new DatagramPacket(buf,buf.length); 
            //3.通过recevice方法将疏导的数据存入数据包中
                ds.receive(dp); //这是阻塞式方法,无数据接收时会停止线程
            //4.通过数据包
                String ip = dp.getAddress().getHostAddress(); //获取数据包中的IP地址
                String data = new String(dp.getData(),0,dp.getLength());//将数据变为字符串
                int port = dp.getPort();//获取数据包中的端口
                System.out.println(ip+"::"+data+":"+port);
            }
            //5.关闭资源
            //ds.close();
        }
    }

    TCP传输
    客户端对应Socket
    服务端对应SerrverSocket

    客户端:通过查阅Socket对象,该对象建立时,就可以去连接指定的主机。
    因为Tcp是面向连接的,所以在建立socket服务时,就需要有服务端存在,
    并连接成功形成通路后,在该通路中进行数据传输。
    步骤:1.建立Socket服务,并指定要连接的主机和端口
    2.获取Socket中的输出流,写入数据后,自动发出
    3.提取Socket中的输入流,获取数据后,操作数据(如:打印)。
    4.关闭客户端
    服务端:1.建立服务端的socket服务,即ServerSocket,并监听一个端口。
    2.通过accept()获取连接过来的客户端对象。该方法为阻塞式的,没有连接会自动等待。
    3.客户端发过来对象,服务端使用对应客户端对象,并获取该客户端对象的输入流获取数据,
    获取该客户端对象的输出流,写入数据,自动发送给客户端。
    4.关闭服务端。

    演示TCP的传输的客户端和服务端的互访。
    需求:客户端给服务器端发送数据,服务端收到,给客户端反馈信息。

    客户端:
    1.建立socket服务,指定要连接的主机和接口。
    2获取socket流中的输出流,将数据写入到该流中,通过网络发送给服务端。
    3.获取socket流中的输入流,将服务端反馈的数据获取到,并打印
    4.关闭客户端
    服务端:
    1.建立ServerSocket服务,自定要监听的端口
    2.从Socket中获取输入流和输出流
    3.从输入流中读取客户端传过来的数据并操作
    4.将数据写入输出流并传给客户端
    5.关闭服务端

    import java.io.*;
    import java.net.*;
    class TcpClient
    {
        public static void main(String [] args) throws Exception
        {
            Socket s = new Socket("192.168.0.100",10001);   //建立Socket服务,指定连接的主机和端口
            OutputStream out = s.getOutputStream();            //获取Socket中的输出流
            out.write("服务端,你好".getBytes());            //写入需要输出的数据
            InputStream in = s.getInputStream();            //获取Socket中的输入流
            byte[] buf = new byte[1024];                    //定义字节数组
            int len = in.read(buf);                            //将输入流中的数据写入字节数组
            System.out.println(new String(buf,0,len));        //将字节数组转为字符串并在控制台上打印
            s.close();                                        //关闭资源
        }
    }
    class TcpServer
    {
        public static void main(String [] args) throws Exception
        {
            ServerSocket ss = new ServerSocket(10001);        //建立服务端ServerSocket对象,指定监听端口
            Socket s = ss.accept();                            //从ServerSockeet中获取Socket对象
            String ip = s.getInetAddress().getHostAddress();//获取Socket中的IP地址
            System.out.println(ip+"....connecting");        //显示正在连接的主机
            InputStream in = s.getInputStream();            //从Socket中获取输入流
            byte[] buf = new byte[1024];                    //定义字节数组
            int len = in .read(buf);                        //将输入流中数据存入字节数组,并将数组有效长度传给len
            System.out.println(new String (buf,0,len));        //将字节数组转为字符串并在控制台上打印
            OutputStream out = s.getOutputStream();            //获取Socket中的输出流
            Thread.sleep(10000);                            //为了掩饰效果,令当亲线程睡一段时间
            out.write("已收到,你也好".getBytes());            //在输入流中写入数据的字节数据
            s.close();                                        //关闭资源
            ss.close();
        }
    }

    需求:建立一个文本转换服务器
    客户端给服务端发送文本,服务端会将文本转成大写并返给客户端
    客户端可以一直输入,直至客户端输入over,关闭客户端和服务端。
    分析:
    客户端:既然是操作设备上的数据,那么久可以使用io技术,并按照io的操作规律来思考
    源:键盘录入
    目的:网络设备,网络输出流
    操作文本数据,选择字符流。
    步骤:
    1.建立服务
    2.获取键盘录入
    3.将数据发给服务端
    4,获取服务端返回的大写数据
    5.关闭数据

    本例中出现问题
    现象:客户端和服务端都在莫名等待
    因为客户端和服务端中都有阻塞式方法,这些方法无结束标记,就会一直等待而导致两端都在等待。
    出现此种现象,优先查询阻塞式方法。

    import java.io.*;
    import java.net.*;
    class TransClient
    {
        public static void main(String[] args) throws Exception
        {
            Socket s = new Socket("192.168.0.100",10005);
            //定义读取键盘的流对象
            BufferedReader bufr =
                new BufferedReader(new InputStreamReader(System.in));
            //定义目的并与Socket对象中的输出流关联
            BufferedWriter bufw =
                new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
            //定义获取服务端的返回的数据(字节流转换成字符流)
            BufferedReader bufr1 =
                new BufferedReader(new InputStreamReader(s.getInputStream()));
            String line = null;
            while ((line=bufr.readLine())!=null)//按行读取输入流中的数据
            {
                if (line.equals("over"))        //定义结束标识
                    break;
                bufw.write(line);                //在输出流中写入数据
                bufw.newLine();                    //换行
                bufw.flush();                    //刷新缓冲区
                String lines = bufr1.readLine();//在lines中写入服务端返回的数据
                System.out.println("server:"+lines);
            }
            bufr.close();                        //关闭资源
            bufw.close();
            bufr1.close();
            s.close();
        }
    }
    class TransServer
    {
        public static void main(String[] args) throws Exception
        {
            ServerSocket ss = new ServerSocket(10005);    //创建SeverSocket对象并指定监听端口
            Socket s = ss.accept();                        //从ServerSocket中获取Socket对象
            String ip = s.getInetAddress().getHostAddress();//获取IP地址
            System.out.println(ip+"....connecting");    //显示正在连接的主机
            BufferedReader bufr =          //定义源
                new BufferedReader(new InputStreamReader(s.getInputStream()));
            BufferedWriter bufw =          //定义目的
                new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
            String line = null;
            while ((line=bufr.readLine())!=null)        //按行读取输入流中的数据
            {
                if (line.equals("over"))                //定义结束标识
                    break;            
                System.out.println("client:"+line);        //打印当前客户端传输过来的数据
                bufw.write(line.toUpperCase());            //在输出流中写入读取数据的大写形式
                bufw.newLine();                            //换行
                bufw.flush();                            //刷新缓存区
            }
                ss.close();                                //关闭资源
                s.close();
                bufr.close();
        }
    }

    需求:上传图片
    为保证图片质量用TCP
    客户端:
    1.建立服务端点
    2.读取客户端已有图片数据
    3.通过Socket输出流将数据发个服务端
    4.读取服务端反馈后关闭。

    服务端
    这个服务端有个局限性,一次只能连接一个客户端
    为了让多个客户端并发访问服务端。
    那么服务端最好就是将每个客户端封装到一个单独的线程中,这样就可以同时处理多个客户端。
    具体实现:
    明确每个客户端要在服务端执行的代码,将其存入run方法。

    import java.io.*;
    import java.net.*;
    class PicClicent
    {
        public static void main(String[] args) throws Exception
        {
            Socket s= new Socket("192.168.0.100",10006);        //定义Socket对象并指定连接主机和端口
            FileInputStream fi = new FileInputStream ("d:\1.jpg");    //定义输入流并关联需操作文件
            OutputStream out = s.getOutputStream();                //从Socket中获取输出流
            byte[] byt = new byte[1024];                        //定义字节数组
            int len = 0;    
            while ((len=fi.read(byt))!=-1)                        //通过循环,将输入流数据存入字节数组
            {
                out.write(byt,0,len);                            //并依次写入输出流,传给服务端
            }
            s.shutdownOutput();                                    //关闭Socket中的输出流
            InputStream in = s.getInputStream();                //获取Socket中的输入流
            byte[] bytin = new byte[1024];                        //定义字节数组
            int num = in.read(bytin);                            //读取字节数组的数据
            System.out.println(new String(bytin,0,num));        //转换成字符串后再控制台上打印
            fi.close();                                            //关闭资源
            s.close();    
        }
    }
    class PicServer
    {
        public static void main(String[] args) throws Exception
        {
            ServerSocket ss = new ServerSocket (10006);            //定义ServerSocket对象并监听指定端口
            while (true)                                        //通过循环多次调用
            {
                Socket s = ss.accept();                            //获取ServerSocket中的Socket对象
                new Thread (new PicThread(s)).start();            //开启复制服务线程
            }
            //ss.close();    
        }
    }
    class PicThread implements Runnable    //定义图片复制操作线程类
    {
        private Socket s;
        PicThread (Socket s)    //将Socket对象传给线程类
        {
            this.s = s;
        }
        public void run()        //覆写run方法,定义需多线程操作的代码
        {
            try
            {
                String ip = s.getInetAddress().getHostAddress();    //获取Socket对象的IP地址
                System.out.println(ip+"....connecting");            //显示正在连接的主机
                InputStream in = s.getInputStream();                //获取Socket对象的输入流
                File file = new File(ip+".jpg");                    //定义新文件为按照IP地址命名
                FileOutputStream fo =new FileOutputStream(file);    //定义输出流与文件关联
                byte[] byt = new byte[1024];                        //定义字节数组
                int len = 0;                                    
                while ((len=in.read(byt))!=-1)                        //通过循环将输入流中的数据依次写入文件
                {
                    fo.write(byt,0,len);
                }
                OutputStream out =s.getOutputStream();                //获取Socket中的输出流
                out.write("上传成功".getBytes());                    //在输出流中写入文件复制成功的提示信息
                fo.close();                                            //关闭资源
                s.close();
            }
            catch (Exception e)
            {
                throw new RuntimeException(e);
            }
        }
    } 
  • 相关阅读:
    2020年4月4日训练
    HZNU Training 17 for Zhejiang Provincial Competition 2020
    [kuangbin带你飞]专题四 最短路练习
    三分法
    洛谷多校第一周续
    洛谷春季 ACM 多校训练第五周
    简单数学三月小结
    线段树&树状数组
    图论三月小结
    Java中Double保留后小数位的几种方法
  • 原文地址:https://www.cnblogs.com/myblog-cl/p/4748626.html
Copyright © 2011-2022 走看看