黑马程序员——Java语言:网络编程

------- <a href="http://www.itheima.com" target="blank">android培训</a>、<a href="http://www.itheima.com" target="blank">java培训</a>、期待与您交流! ----------


网络编程


一、概述

1.1 网络参考模型

OSI参考模型

TCP/IP参考模型


1.2 网络通讯要素

1. IP地址:InetAddress

网络中设备的标识。

不易记忆,可用主机名。

本地回环地址:127.0.0.1 主机名:localhost

2. 端口号

用于标识进程(应用程序)的逻辑地址,不同进程的标识。

有效端口:0~65535,其中0~1024系统使用或保留端口。

3. 传输协议

通讯的规则。

常见协议:UDPTCP

UDP

将数据及源和目的封装成数据包中,不需要建立连接。

每个数据报的大小在限制在64k内。

因无连接,是不可靠协议。

不需要建立连接,速度快。

TCP

建立连接,形成传输数据的通道。

在连接中进行大数据量传输。

通过三次握手完成连接,是可靠协议。

必须建立连接,效率会稍低。

[java]  view plain copy
  1. import java.net.*;  
  2. class  IPDemo  
  3. {  
  4.     public static void main(String[] args) throws Exception  
  5.     {  
  6.         InetAddress i = InetAddress.getLocalHost();  
  7.           
  8.         //System.out.println(i.toString());  
  9.         System.out.println(i.getHostName());  
  10.         System.out.println(i.getHostAddress());  
  11.     }  
  12. }  

二、传输协议

2.1 Socket

Socket就是为网络服务提供的一种机制。

通信的两端都有Socket

网络通信其实就是Socket间的通信。

数据在两个Socket间通过IO传输。

2.2 UDP传输协议

方法: 

创建 UDPSocket发送服务对象:

DatagramSocket(),不指定端口。DatagramSocket(int port),指定端口。

发送:void send(DatagramPacket p)

接收:void receive(DatagramPacket p)

 

定义UDP发送端

方法:

1.建立UDP socket服务

2.提供数据,并将数据封装到数据包中

3.通过socket服务的发送功能,并将数据包发送出去

4.关闭资源

[java]  view plain copy
  1. import java.net.*;  
  2. import java.io.*;  
  3. class  UDPSend  
  4. {  
  5.     public static void main(String[] args) throws Exception  
  6.     {  
  7.         //1.创建UDP服务,通过DatagramSocket对象  
  8.         DatagramSocket ds = new DatagramSocket(8888);  
  9.   
  10.         //2.确定数据,并封装成数据包。(键盘录入)  
  11.         //DatagramPacket(byte[] buf, int length, InetAddress address, int port)   
  12.         //构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号。  
  13.         BufferedReader bfr =   
  14.             new BufferedReader(new InputStreamReader(System.in));  
  15.           
  16.         String line = null;  
  17.   
  18.         while((line=bfr.readLine())!=null)  
  19.         {  
  20.             if("over".equals(line))  
  21.                 break;  
  22.             byte[] buf = line.getBytes();  
  23.   
  24.             DatagramPacket dp =   
  25.                 new DatagramPacket(buf,buf.length,InetAddress.getByName("10.0.0.2"),10000);  
  26.           
  27.             //3.通过Socket服务将已有数据包发送出去,通过send方法  
  28.             ds.send(dp);  
  29.               
  30.         }  
  31.   
  32.         //4.关闭资源  
  33.         ds.close();  
  34.   
  35.     }  
  36. }  

定义UDP接收端

方法:

1.建立UDP socket服务。通常会监听一个端口,其实就是给这个接受网络应用程序

定义数字标识,方便于明确哪些数据过来该应用可以处理

2.定义一个数据包,用来存储接收到的字节数据。

因为数据包对象中有更多功能可以提取字节数据中的不同数据信息

3.通过socket服务的接收功能将收到的数据存入已定义好的数据包中

4.通过数据包的特有功能,将这些不同的数据取出,打印在控制台上

5.关闭资源

[java]  view plain copy
  1. import java.net.*;  
  2. class  UDPRec  
  3. {  
  4.     public static void main(String[] args)  throws Exception  
  5.     {  
  6.         //1.创建UDP socket,建立端点  
  7.         DatagramSocket ds = new DatagramSocket(10000);  
  8.   
  9.         while(true)  
  10.         {  
  11.             //2.定义数据包,用于存储数据  
  12.             byte[] buf = new byte[1024];  
  13.             DatagramPacket dp = new DatagramPacket(buf,buf.length);  
  14.   
  15.             //3.通过receive方法将数据存入到数据包中  
  16.             ds.receive(dp); //阻塞式方法  
  17.   
  18.             //4.通过数据包的方法获取其中的数据  
  19.             String ip = dp.getAddress().getHostAddress();  
  20.   
  21.             String data = new String(dp.getData(),0,dp.getLength());  
  22.   
  23.             int port = dp.getPort();  
  24.   
  25.             System.out.println(ip+"+"+data+"+"+port);  
  26.   
  27.             ds.close();  
  28.         }  
  29.     }  
  30. }  

由于UDP协议传输数据,只管发送数据,而不管接收端是否能够接收到数据。因此,应该首先启动接收端程序,再启动发送端程序。

练习:编写一个聊天程序

[java]  view plain copy
  1. import java.io.*;  
  2. import java.net.*;  
  3. import java.util.*;  
  4. class ChatDemo  
  5. {  
  6.     public static void main(String[] args)  throws Exception  
  7.     {  
  8.         DatagramSocket sendSocket = new DatagramSocket(9999);  
  9.         DatagramSocket recSocket = new DatagramSocket(10003);  
  10.           
  11.         new Thread(new Send(sendSocket)).start();  
  12.         new Thread(new Rec(recSocket)).start();  
  13.           
  14.     }  
  15. }  
  16.   
  17. class Send implements Runnable  
  18. {  
  19.     private DatagramSocket ds;  
  20.     Send(DatagramSocket ds)  
  21.     {  
  22.         this.ds = ds;  
  23.     }  
  24.     public void run()  
  25.     {  
  26.         try  
  27.         {  
  28.             BufferedReader bur =   
  29.                 new BufferedReader(new InputStreamReader(System.in));  
  30.             String line = null;  
  31.             while((line=bur.readLine())!=null)  
  32.             {  
  33.                 if("over".equals(line))  
  34.                     break;  
  35.                 byte[] buf = line.getBytes();  
  36.                 DatagramPacket dp =   
  37.                     new DatagramPacket(buf,buf.length,InetAddress.getByName("10.0.0.2"),10003);  
  38.                 ds.send(dp);  
  39.             }  
  40.         }  
  41.         catch (Exception e)  
  42.         {  
  43.             throw new RuntimeException("发送失败");  
  44.         }  
  45.           
  46.           
  47.     }  
  48. }  
  49.   
  50. class Rec implements Runnable  
  51. {  
  52.     private DatagramSocket ds;  
  53.     Rec(DatagramSocket ds)  
  54.     {  
  55.         this.ds = ds;  
  56.     }  
  57.   
  58.     public void run()  
  59.     {  
  60.         try  
  61.         {  
  62.             while(true)  
  63.             {  
  64.                 byte[] buf = new byte[1024];  
  65.                 DatagramPacket dp =   
  66.                     new DatagramPacket(buf,buf.length);  
  67.                 ds.receive(dp);  
  68.                   
  69.                 String ip = dp.getAddress().getHostAddress();  
  70.                 String data = new String(dp.getData(),0,dp.getLength());  
  71.                 System.out.println(ip+":"+data);  
  72.   
  73.             }  
  74.         }  
  75.         catch (Exception e)  
  76.         {  
  77.             throw new RuntimeException("接收失败");  
  78.         }  
  79.     }  
  80. }  

2.3  TCP传输协议

客户端(Client)首先与服务端(Server)建立连接,形成通道(其实就是IO流),然后,数据就可以在通道之间进行传输,并且单个Server端可以同时与多个Client端建立连接。

方法:

创建客户端对象:

Socket():创建空参数的客户端对象,一般用于服务端接收数据

Socket(String host,int port),指定要接收的IP地址和端口号

创建服务端对象:ServerSocket(int port):指定接收的客户端的端口

Socket accept():监听并接受到此套接字的连接

void shutdownInput():此套接字的输入流至于“流的末尾”

void shutdownOutput():禁用此套接字的输出流

InputStream getInputStream():返回此套接字的输入流,Socket对象调用

OutputStream getOutputStream():返回套接字的输出流,Socket对象调用

TCP客户端

客户端需要明确服务器的ip地址以及端口,这样才可以去试着建立连接,如果连接失败,会出现异常。连接成功,说明客户端与服务端建立了通道,那么通过IO流就可以进行数据的传输,而Socket

对象已经提供了输入流和输出流对象,通过  getInputStream(),getOutputStream()获取即可。与服务端通讯结束后,关闭Socket

[java]  view plain copy
  1. import java.net.*;  
  2. import java.io.*;  
  3. class  TCPClient  
  4. {  
  5.     public static void main(String[] args) throws Exception  
  6.     {  
  7.         //创建客户端socket,一旦建立就有了输入流和输出流  
  8.         Socket s = new Socket("10.0.0.2",10004);  
  9.         //获取socket流中的输出流  
  10.         OutputStream out = s.getOutputStream();  
  11.   
  12.         out.write("TCP coming".getBytes());  
  13.   
  14.         s.close();  
  15.     }  
  16. }  

TCP服务端

服务端需要明确它要处理的数据是从哪个端口进入的。当有客户端访问时,要明确是哪个客户端,可通过accept()获取已连接的客户端对象,并通过该对象与客户端通过IO流进行数据传输。当该客户端访问结束,关闭该客户端。

[java]  view plain copy
  1. class TCPServer  
  2. {  
  3.     public static void main(String[] args) throws Exception  
  4.     {  
  5.         ServerSocket ss = new ServerSocket(10004);  
  6.   
  7.         Socket s = ss.accept();  
  8.   
  9.         String ip = s.getLocalAddress().getHostAddress();  
  10.   
  11.         System.out.println(ip);  
  12.   
  13.         InputStream  in = s.getInputStream();  
  14.   
  15.         byte[] buf = new byte[1024];  
  16.   
  17.         int len = in.read(buf);  
  18.   
  19.           
  20.         String data = new String(buf,0,len);  
  21.   
  22.         System.out.println(data);  
  23.   
  24.         s.close();//关闭客户端  
  25.         ss.close();  
  26.     }  
  27.       
  28. }  

TCP协议-服务端和客户端交互

[java]  view plain copy
  1. import java.io.*;  
  2. import java.net.*;  
  3.   
  4. class Send  
  5. {  
  6.     public static void main(String[] args) throws Exception  
  7.     {  
  8.         Socket s = new Socket("10.0.0.2",10006);  
  9.         //发送数据  
  10.         OutputStream out = s.getOutputStream();  
  11.         out.write("HELLO HOST".getBytes());  
  12.         //接受反馈  
  13.         InputStream in = s.getInputStream();  
  14.         byte[] buf = new byte[1024];  
  15.         int len = in.read(buf);  
  16.         System.out.println(new String(buf,0,len));  
  17.         s.close();  
  18.     }  
  19. }  
  20.   
  21. class Server  
  22. {  
  23.     public static void main(String[] args) throws Exception  
  24.     {  
  25.         ServerSocket ss = new ServerSocket(10006);  
  26.         Socket s = ss.accept();  
  27.         String ip = s.getLocalAddress().getHostAddress();  
  28.         System.out.println(ip+" is connecting");  
  29.         //接受数据  
  30.         InputStream in = s.getInputStream();  
  31.         byte[] buf = new byte[1024];  
  32.         int len = in.read(buf);  
  33.         System.out.println(new String(buf,0,len));  
  34.         //发送反馈  
  35.         OutputStream out = s.getOutputStream();  
  36.         Thread.sleep(1000);  
  37.         out.write("RECIVED".getBytes());  
  38.         s.close();  
  39.         ss.close();  
  40.     }  
  41. }  

TCP练习:需求:建立一个文本转换服务器,客户端给服务端发送文本,服务端会将文本转成大写再返回给客户端。而且客户端可以不断的进行文本转换,当输入over时结束。

[java]  view plain copy
  1. import java.io.*;  
  2. import java.net.*;  
  3. class  TransSend  
  4. {  
  5.     public static void main(String[] args)  throws Exception  
  6.     {  
  7.         //定义socket服务  
  8.         Socket s = new Socket("10.0.0.2",10007);  
  9.           
  10.         //键盘录入流  
  11.         BufferedReader bfr =   
  12.             new BufferedReader(new InputStreamReader(System.in));  
  13.           
  14.         //定义目的,将数据写入socket输出流发送给服务端  
  15.         //BufferedWriter bfwOut =   
  16.         //  new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));  
  17.   
  18.         PrintWriter out = new PrintWriter(s.getOutputStream(),true);  
  19.           
  20.         //定义一个socket读取流,读取服务端返回的信息  
  21.         BufferedReader bfrIn =  
  22.             new BufferedReader(new InputStreamReader(s.getInputStream()));  
  23.   
  24.         String line =null;  
  25.   
  26.         while((line=bfr.readLine())!=null)  
  27.         {  
  28.             if("over".equals(line))  
  29.                 break;  
  30.   
  31.             out.println(line);  
  32.             //bfwOut.write(line);  
  33.             //bfwOut.newLine();  
  34.             //bfwOut.flush();  
  35.   
  36.             String str = bfrIn.readLine();  
  37.               
  38.             System.out.println("返回:"+str);  
  39.         }  
  40.   
  41.         bfr.close();  
  42.         s.close();  
  43.     }  
  44. }  
  45.   
  46. class TransServer  
  47. {  
  48.     public static void main(String[] args) throws Exception  
  49.     {  
  50.         ServerSocket ss = new ServerSocket(10007);  
  51.         Socket s = ss.accept();  
  52.         String ip = s.getInetAddress().getHostAddress();  
  53.         int port = s.getPort();  
  54.         System.out.println(ip+"   "+port);  
  55.         BufferedReader bfr =   
  56.             new BufferedReader(new InputStreamReader(s.getInputStream()));  
  57.   
  58.         //BufferedWriter bfw =  
  59.         //  new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));  
  60.   
  61.         PrintWriter out = new PrintWriter(s.getOutputStream(),true);  
  62.   
  63.         String line = null;  
  64.         while((line=bfr.readLine())!=null)  
  65.         {  
  66.             System.out.println(line);  
  67.             out.println(line.toUpperCase());  
  68.             //bfw.write(line.toUpperCase());  
  69.             //bfw.newLine();  
  70.             //bfw.flush();  
  71.         }  
  72.   
  73.         s.close();  
  74.         ss.close();  
  75.     }  
  76. }  

常见问题:

1、上面练习中之所以客户端结束后,服务端也随之结束的原因在于:客户端的socket关闭后,服务端获取的客户端socket读取流也关闭了,因此读取不到数据,line = bfr.readLine()null,循环结束,ServerSocketclose方法也就

执行关闭了。

2、上面练习中的客户端和服务端的PrintWriter对象out获取到数据后,一定要刷新,否则对方(服务端或客户端)就获取不到数据,程序便无法正常执行。刷新操作可以通过PrintWriter类的println()方法实现,也可以通过PrintWriter类的flush()方法实现。但是,由于获取数据的方法是BufferedReader对象bfrreadLine()方法(阻塞式方法),此方法只有遇到“\r\n”标记时,才认为数据读取完毕,赋值给String对象line。所以,使用PrintWriter类的flush()方法刷新数据时一定要记得追加“\r\n”。

三、了解客户端和服务器端原理

最常见的客户端:浏览器,IE/chrome

最常见的服务端:服务器,Tomcat

客户端发送的请求是:

(请求行,请求方式:GET;请求的资源路径:/HTTP协议版本:1.1。)

GET / HTTP/1.1

(请求消息头,属性名:属性值。)

Host: localhost:9090

Connection: keep-alive

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8

User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like

Gecko) Chrome/43.0.2357.81 Safari/537.36

Accept-Encoding: gzip, deflate, sdch

Accept-Language: zh-CN,zh;q=0.8

HTTP服务端发回的应答消息:

(应答行,HTTP的协议版本:1.1;应答状态码:200;应答状态描述信息:OK。)

HTTP/1.1 200 OK

(应答消息属性信息,属性名:属性值。)

Server: Apache-Coyote/1.1

Accept-Ranges: bytes

ETag: W/"211-1433908112666"

Last-Modified: Wed, 10 Jun 2015 03:48:32 GMT

Content-Type: text/html

Content-Length: 211

Date: Wed, 10 Jun 2015 03:52:16 GMT

Connection: close 

四、URL&URLConnection

URI:统一资源标示符。

URL:统一资源定位符,也就是说根据URL能够定位到网络上的某个资源,它是指向互联网“资源”的指针。每个URL都是URI,但不一定每个URI都是URL。这是因为URI还包括一个子类,即统一资源名称(URN),它命名资源但不指定如何定位资源。

URL方法:

 构造函数:URL(String protocol,String host,int port,String file);//根据指定 protocolhostport号和 file 创建 URL对象。

String getProtocol();//获取协议名称

String getHost();//获取主机名

int getPort();//获取端口号

String getFile();//获取URL文件名

String getPath();//获取此URL的路径部分

String getQuery();//获取此URL的查询部,客户端传输的特定信息

注:一般输入网址,是不带端口号的,此时可进行获取,通过获取网址返回的port,若port-1,则分配一个默认的80端口

URLConnection方法:

URLConnection openConnection();//URL调用此方法,返回一个 URLConnection 对象,它表示到 URL 所引用的远程对象的连接。

InputStream getInputStream();//获取输入流

OutputStream getOutputStream();//获取输出流

 


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值