黑马程序员--网络编程

来源:互联网 发布:开票软件使用方法 编辑:程序博客网 时间:2024/06/10 08:47

——Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ——-
网络编程:
3要素

IP地址   InetAddress    网络中设备的标识    不易记忆,可用主机名    本地回环地址:127.0.0.1 主机名 localhost端口号      用于标识进程的逻辑地址,不同进程的标识    有效端口:0~65535,其中0-1024系统使用或保留端口传输协议:    通讯的规则    常见:TCP,UDP

InetAddress类描述ip地址的类
该类无构造函数,可以通过静态方法返回本类对象
InetAddress i=InetAddress.getLocalHost();
InetAddress ia=InetAddress.getByName(“www.baidu.com”);
InetAddress[] ias=InetAddress.getAllByName(“www.baidu.com”);

常用方法:getHostName()getHostAddress();

UDP协议

将数据及源和目的封装成数据包中,不需要建立连接每个数据包的大小限制在64K之内因为无连接,是不可靠协议不需要建立连接,速度快.

示例:网络视频会议,聊天等

TCP协议

建立连接,形成传输数据通路在连接中进行大数据量传输通过三次握手完成连接,是可靠协议必须建立连接,效率低

三次握手简单理解:

        李四                      张三1.  张三,你在吗?2.                              我在,李四3.  哦,张三,我知道你在了 

示例:打电话

Socket类

Socket就是为网络服务提供的一种机制通信的两端都有Socket网络通信其实就是Socket间的通信数据在两个Socket间通过IO传输

每个传输协议都有自己的对象

UDP的Socket的建立通过DatagramSocket
该类技能发送也能接收发送
send(DatagramePacket p);
receive(DatagramePacket p);
Udp聊天

/*Udp聊天使用多线程技术发送信息的同时能接收数据因为收和发的动作是不一致的,所以要定义两个run方法而且这两个方法要封装到不同的类中。*/import java.io.*;import java.net.*;class Receive implements Runnable{       private DatagramSocket ds;    public Receive(DatagramSocket ds)    {        this.ds=ds;    }    public void run()    {        try        {            while (true)            {                byte[] buf=new byte[1024];                DatagramPacket dp=new DatagramPacket(buf,buf.length);                ds.receive(dp);                String ip=dp.getAddress().getHostAddress();                String data=new String(dp.getData(),0,dp.getLength());                System.out.println(ip+"..."+data);             }        }        catch (Exception e)        {            throw new RuntimeException("接收失败");        }    }}class Send implements Runnable{       private DatagramSocket ds;    public Send(DatagramSocket ds)    {        this.ds=ds;    }    public void run()    {        try        {            BufferedReader bufr=new BufferedReader(new InputStreamReader(System.in));            String line=null;            while((line=bufr.readLine())!=null)            {                if("886".equals(line))                    break;                byte[] buf=line.getBytes();                DatagramPacket dp=new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.1.101"),10086);                ds.send(dp);            }            ds.close();        }        catch (Exception e)        {            throw new RuntimeException("发送端失败!");        }    }}class ChatDemo {    public static void main(String[] args) throws Exception    {        DatagramSocket udpSend=new DatagramSocket();        DatagramSocket udpRece=new DatagramSocket(10087);        new Thread(new Send(udpSend)).start();        new Thread(new Receive(udpRece)).start();    }}

Tcp有两个对象
客户端:
Socket
该对象建立时,就可以去连接指定主机
因为tcp是面向连接的。所以在建立socket服务时,就要有服务端存在
并连接成功。形成通路后,在该通道进行数据的传输。

服务端:ServerSocket

socket之间的连接一旦建立,又有了一个流。里面包括输入流个输出流,通过getInputStream和getOutputStream获得

/*需求:建立一个文本转换服务器客户端给服务端发送文本,服务端会将文本转成大写返回给客户端。而且客户端可以不断的进行文本转换,输入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.1.101",10006);        //定义读取键盘数据的流对象        BufferedReader bufr=new BufferedReader(new InputStreamReader(System.in));        //定义目的,将数据写入socket输出流。发给服务端        //BufferedWriter bufw=new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));         PrintWriter out=new PrintWriter(s.getOutputStream(),true);        //定义读取socket读取流,读取服务端返回的大写信息        BufferedReader bufIn=new BufferedReader(new InputStreamReader(s.getInputStream()));        String line=null;        while ((line=bufr.readLine())!=null)        {               if("over".equals(line))                break;            out.println(line);            /*            bufw.write(line);            bufw.newLine();//结束标记,在读键盘时一定要定义结束标记。            bufw.flush();//使用缓冲区,一定要注意刷新。            */            String s1=bufIn.readLine();            System.out.println(s1);        }        bufr.close();        s.close();    }}/*服务端源:socket读取流目的:socket输出流都是文本,装饰*/class  TransServer{    public static void main(String[] args) throws Exception    {        ServerSocket ss=new ServerSocket(10006);        Socket s=ss.accept();        String ip=s.getInetAddress().getHostAddress();        System.out.println(ip);        //读取socket读取流中的数据        BufferedReader bufr=new BufferedReader(new InputStreamReader(s.getInputStream()));        //目的。socket输出流。将大写数据写入到socket输出流,并发送给客户端        //BufferedWriter bufw=new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));        PrintWriter out=new PrintWriter(s.getOutputStream(),true);        String line=null;        while ((line=bufr.readLine())!=null)        {            out.println(line.toUpperCase());            /*            bufw.write(line.toUpperCase());            bufw.newLine();//结束标记            bufw.flush();            */        }        s.close();        ss.close();    }}/*该例子出现的问题现象:客户端和服务端都在莫名的等待为什么呢?因为客户端和服务端都有阻塞式方法。这些方法没有读到结束标记,那么就一直等待因而导致,都在等待。*/

注意:在使用TCP传送文件,数据时一定要定义结束标记。
传送文件自定义结束标记的几种方法:
1.在传送完后发送”over”字样,弊端:文本中可能有单独一行是over,不可靠
2.发送文件前先发送结束标记”%^^%&^”,让服务端知道,发送完毕后再发送一次,
有可能和文本中的数据重复
3.在发送之前,拿到当前时间,使用DataOutputStream发送出去,文件发送完后,
再发送一次刚才获取到的时间。服务端根据两次时间判断是否发送完毕。
在TCP传输中java提供了专业方法:
socket提供了专业的处理方法:
void shutdownOutput(); //相当于给流中加入结束标记-1
void shutdownInput();
TCP复制文件:

import java.io.*;import java.net.*;class  TextClient{    public static void main(String[] args)throws Exception     {        Socket s=new Socket("192.168.1.101",10007);        BufferedReader bufr=new BufferedReader(new FileReader("IPDemo.java"));        PrintWriter out=new PrintWriter(s.getOutputStream(),true);        String line=null;        while((line=bufr.readLine())!=null)        {            out.println(line);        }        s.shutdownOutput();//关闭客户端的输出流,相当于给流中加入结束标记-1        BufferedReader br=new BufferedReader(new InputStreamReader(s.getInputStream()));        String str=br.readLine();        System.out.println(str);        bufr.close();        s.close();    }}class  TextServer{    public static void main(String[] args) throws Exception    {        ServerSocket ss=new ServerSocket(10007);        Socket s=ss.accept();        BufferedReader bufr=new BufferedReader(new InputStreamReader(s.getInputStream()));        PrintWriter out=new PrintWriter(new FileWriter("server.txt"),true);        String line=null;        while ((line=bufr.readLine())!=null)        {            out.println(line);        }        PrintWriter pw=new PrintWriter(s.getOutputStream(),true);        pw.println("上传成功!");        s.close();        ss.close();    }}

综合案例:TCP上传图片(多人同时上传)

/*客户端:1.建立服务端点2.读取客户端已有的图片数据3.通过Socket输出流将数据发送给服务端4.读取服务端反馈信息5.关闭*/import java.io.*;import java.net.*;class Client {    public static void main(String[] args)throws Exception     {        //采用主函数传值的形式给将图片的路径传入           if(args.length!=1)        {            System.out.println("请选择一个bmp格式的图片");            return;        }        File file=new File(args[0]);        if(!(file.exists()&&file.isFile()))        {            System.out.println("该文件有问题,要么不存在,要么不是文件");            return;        }        if(!file.getName().endWith(".bmp"))        {            System.out.println("图片格式错误,清重新选择");            return;        }        if(file.length()>1024*1024*5)        {            System.out.println("文件过大,没安好心");            return;        }        Socket s=new Socket("192.168.1.101",10008);        BufferedInputStream bis=new BufferedInputStream(new FileInputStream(file));        BufferedOutputStream bos=new BufferedOutputStream(s.getOutputStream());        byte[] buf=new byte[1024];        int len=0;        while ((len=bis.read(buf))!=-1)        {            bos.write(buf,0,len);            bos.flush();        }        s.shutdownOutput();        BufferedReader bufr=new BufferedReader(new InputStreamReader(s.getInputStream()));        String line=bufr.readLine();        System.out.println(line);        bis.close();        s.close();    }}/*服务端:这个服务端有个局限性,当A客户端连接上以后,被服务端获取到。服务端执行具体流程这是B客户连接,只有等待。以为服务端还没有处理完A客户端的请求,还有循环回来执行下次accept方法。所有已暂时执行不到B客户端对象。那么为了可以让对个客户端同时并发访问服务端。那么服务端最好就是将每个客户端封装到一个单独的线程中,这样,就可以同时处理多个客户端请求。那么如何定义线程呢?只要明确了每一个客户端要在服务端执行的代码即可。将该代码存入run方法中。*/class PicThread implements Runnable{    private Socket s;    PicThread(Socket s)    {        this.s=s;    }    public void run()    {        try        {            int count=1;            String ip=s.getInetAddress().getHostAddress();            System.out.println(ip);            File file=new File(ip+"("+count+")"+".bmp");            while(file.exists())                file=new File(ip+"("+(count++)+")"+".bmp");            BufferedInputStream bis=new BufferedInputStream(s.getInputStream());            //定义一个输出流,绑定一个文件            BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream(file));            byte[] buf=new byte[1024];            int len=0;            while ((len=bis.read(buf))!=-1)            {                bos.write(buf,0,len);                bos.flush();            }            PrintWriter pw=new PrintWriter(s.getOutputStream(),true);            pw.println("你已经上传成功了!");            bos.close();            s.close();                  }        catch (Exception e)        {            throw new RuntimeException("上传失败!");        }    }}class Server {    public static void main(String[] args)throws Exception    {        ServerSocket ss=new ServerSocket(10008);        while (true)        {            Socket s=ss.accept();            new Thread(new PicThread(s)).start();        }    }}

URL类:可以对网址进行多种操作

 String getFile()           获取此 URL 的文件名。  String getHost()           获取此 URL 的主机名(如果适用)。  String getPath()           获取此 URL 的路径部分。  int getPort()           获取此 URL 的端口号。  String getProtocol()           获取此 URL 的协议名称。  String getQuery()           获取此 URL 的查询部分。
    public static void main(String[] args) throws Exception    {        //当url中没有port即下面的8080,会自动分配一个端口80,即我们上网的时候访问的都是默认的80端口        URL url=new URL("http://192.168.1.101:8080/myweb/demo.html?name=haha&age=30");         System.out.println("getHost:"+url.getHost());        System.out.println("getPath:"+url.getPath());        System.out.println("getFile:"+url.getFile() );        System.out.println("getPort:"+url.getPort());        System.out.println("getProtocol:"+url.getProtocol());        System.out.println("getQuery:"+url.getQuery());    }

url中也提供了
OpenStream()方法
相当于openConnection().getInputStream()

/*读取一个页面的源码*/import java.io.*;import java.net.*;class URLConnectionDemo {    public static void main(String[] args) throws Exception    {        URL url=new URL("http://www.baidu.com");        URLConnection conn=url.openConnection();        //该类把请求头和服务端返回回来的信息都封装了,只显示正文内容        System.out.println(conn);        InputStream in=conn.getInputStream();        byte[] buf=new byte[1024];        int len=0;        while ((len=in.read(buf))!=-1)        {            System.out.println(new String(buf,0,len));        }    }}

域名解析:
域名解析:
在ie浏览器上输入
1.http://192.168.1.254:8080/myweb/demo.html
2.http://www.baidu.com
如果输入的是ip地址,浏览器会直接去连接该ip,如果输入的是网址,即主机名
浏览器会先先从本地找c:\window\systems\dirvers\ext\host,
获取里面的映射信息,查看是否有对应的ip,如果有则根据拿到的ip直接连接
如果没有,会去找DNS域名解析器,从里面获取主机名对应的ip地址从而进行连接。

知道了本地c:\window\systems\dirvers\ext\host内部有映射关系之后,我们就可以改变里面的信息达到

1.屏蔽网站 将网站对应的ip地址改为本地,就访问不到对应网站2.连接网站速度加快3.不让收费软件自动更新
0 0
原创粉丝点击