黑马程序员_网络编程

来源:互联网 发布:辗转相减法 vb 编辑:程序博客网 时间:2024/05/12 12:30

-------android培训、java培训、期待与您交流!-------

网络编程

1、网络编程基础知识

(1)网络主要功能

A、资源共享

B、信息传输与集中处理

C、均衡负荷与分布处理

D、综合信息服务

(2)网络通讯要素

A、传输协议

目前的写有OSI与TCP/IP,OSI把计算机网络分为七层,TCP/IP协议将网络分为四层。

OSI模型

          应用层

          表示层

          会话层

          传输层

          网络层

          数据连接层

          物理层

TCP/IP模型

          应用层

          传输层

          网际层

          主机至网络层

 

B、IP地址

概述:IP地址用于唯一地标识网络中的一个通信实体,这个通信实体可以是一台主机、打印机、路由端口等。

IP地址 = 网络号码+主机地址

A类:1.0.0.1---127.255.255.254 10.X.X.X是私有地址(私有地址就是在互联网上不使用,而被用在局域网络中的地址)

B类:128.0.0.1---191.255.255.254  172.16.0.0---172.31.255.255是私有地址。169.254.X.X是保留地址。

C类:192.0.0.1---223.255.255.254  192.168.X.X是私有地址

D类:224.0.0.1---239.255.255.254

E类:240.0.0.1---247.255.255.254

※注意:

1)127.0.0.1 回环地址,可用于测试本机的网络是否有问题. ping 127.0.0.1

IP地址不能够是广播地址或者网络地址,所以要遵守如下规则:

IP地址网络地址不能全部设置为“1”或“0”

IP地址子网地址不能全部设置为“1”或“0”

IP地址主机地址不能全部设置为“1”或“0”

2)E类地址是保留地址。

C、端口号

端口号是一个十六位整数,用于表示数据交给那个通信程序处理。端口就是应用程序与外界交流的出入口,它是一种抽象的软件结构,包括一些数据结构和I/O缓冲区。

0-1023为公认端口。他们紧密绑定一些特定服务。

1024-49151为注册端口。应用程序应该使用这个范围的端口。

49152-65535为动态或者私有端口,这些端口是应用程序使用的动态端口,应用程序一般不会主动使用这些端口。

(3)网络通讯前提:

A、找到对方IP数据要发送到指定端口。为了标示不同的应用程序,所以给这些网络应用程序都用数字进行标识。这个表示就叫端口。

B、定义通信规则。这个规则称为通信协议,国际组织定义了通用协议TCP/IP

2、TCP和UDP

(1)UDP和TCP的区别:

A、UDP

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

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

因无连接,是不可靠协议

不需要建立连接,速度快

B、TCP

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

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

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

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

注:三次握手:

       第一次:我问你在么?

       第二次:你回答在。

       第三次:我反馈哦我知道你在。

3、Socket(UDP传输)

要点:

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

通信的两端都有Socket。

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

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

玩Socket主要就是记住流程,代码查文档就行

4、UDP传输:DatagramSocket与DatagramPacket

A、发送端:

       建立DatagramSocket服务;

       提供数据,并将数据封装到字节数组中;

       创建DatagramPacket数据包,并把数据封装到包中,同时指定IP和接收端口

       通过Socket服务,利用send方法将数据包发送出去;

       关闭DatagramSocket和DatagramPacket服务。

B、接收端:

       建立DatagramSocket服务,并监听一个端口;

       定义一个字节数组和一个数据包,同时将数组封装进数据包;

       通过DatagramPacket的receive方法,将接收的数据存入定义好的数据包;

       通过DatagramPacke相关的方法,获取发送数据包中的信息;

       关闭DatagramSocket和DatagramPacket服务。

C、DatagramSocket与DatagramPacket方法摘要:

(1)构造方法:

       DatagramSocket()

          构造数据报套接字并将其绑定到本地主机上任何可用的端口。

       DatagramSocket(int port)

          创建数据报套接字并将其绑定到本地主机上的指定端口。

       DatagramSocket(int port, InetAddress laddr)

          创建数据报套接字,将其绑定到指定的本地地址。

(2)方法摘要:

       void close()//关闭此数据报套接字。

       InetAddress getInetAddress()//  返回此套接字连接的地址。

       InetAddress getLocalAddress() //获取套接字绑定的本地地址。

       int getPort() //返回此套接字的端口。

       void receive(DatagramPacket p) //从此套接字接收数据报包。

       void send(DatagramPacket p) //从此套接字发送数据报包。

D、DatagramPacket

(1)构造方法:

       DatagramPacket(byte[] buf, int length) //构造 DatagramPacket,用来接收长度为 length 的数据包。

       DatagramPacket(byte[] buf, int length, InetAddress address, int port) //构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号。

       InetAddress getAddress()//返回某台机器的 IP 地址,此数据报将要发往该机器或者是从该机器接收到的。

       byte[] getData() //返回数据缓冲区。

       int getLength() //返回将要发送或接收到的数据的长度。

       int getPort() //返回某台远程主机的端口号,此数据报将要发往该主机或者是从该主机接收到的。  

典型例题:

发送端:

package net;import java.net.DatagramPacket;import java.net.DatagramSocket;import java.net.InetAddress;public class UdpSend{/** * 需求:通过UDP方式,将一段文字数据发送出去。1.首先建立一个UDPSocket服务 2.提供数据将数据封装到包中3.通过Socket服务将数据发出。4.关闭Socket服务; * @param args */public static void main(String[] args) throws Exception{//1、创建UDP服务,通过DatagramSocket对象DatagramSocket ds = new DatagramSocket(8888);byte[] buf = "sdfsdfsdf".getBytes();//2、确定数据并且封装成数据包DatagramPacket dp = new DatagramPacket(buf, buf.length, InetAddress.getByName("192.168.0.104"), 20000);ds.send(dp);//3、使用已经存在的Socket服务,将数据包对象发送出去ds.close();//4、使用已经存在的UDPSocket服务将数据关闭}}


接收端:

package net;import java.net.DatagramPacket;import java.net.DatagramSocket;public class UDPRece{/** * 需求:定义应用程序,用于接收udp协议传输的数据并处理。 1.定义一个UDPSocket服务。 * 2.定义一个数据包,因为要存取接收到的字节数据,因为数据包对象中封装有多种方法,方便我们提取字节数据中的内容。 * 3.通过UDPSocket服务,调用receive()方法将 接收到的数据存入数据包中。 * 4.通过数据包特有的方法,将我们需要的数据提取出来打印在控制台上。 5.关闭资源。 *  * @param args */public static void main(String[] args) throws Exception{DatagramSocket ds = new DatagramSocket(20000);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="+ip+"--data="+data+"---prot="+dp.getPort());}}


 

需求:编写简单的聊天工具

       思路:使用多线程技术

       发送端:

class UDPSend implements Runnable{private DatagramSocket ds;public UDPSend(){}public UDPSend(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[] buff = line.getBytes();DatagramPacket dp = new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.1.104"),10001);ds.send(dp);}}catch(Exception e){throw new RuntimeException("发送失败");}}}


接收端:

class UDPRece implements Runnable{private DatagramSocket ds;public UDPSend(){}public UDPSend(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().getHosyAddress();//获取发送端的ipString data = new String(dp.getData(),0,dp.getLength());//获取数据int port = dp.getPort();//获取发送端的端口号sop(ip+":"+data+":"+port);}}catch(Exception e){throw new RuntimeException("接收失败");}}}


测试类:

class UDPTest{public static void main(String[] args){DatagramSocket sendSocket = new DatagramSocket();DatagramSocket receSocket = new DatagramSocket(10001);new Thread(new UDPSend(sendSocket)).start();new Thread(new UDPRece(receSocket)).start();}}


 

5、TCP传输

       Socket和ServerSocket

       建立客户端和服务器端

       建立连接后,通过Socket中的IO流进行数据的传输

       关闭socket

       同样,客户端与服务器端是两个独立的应用程序。

(1)Socket

A、构造方法:

       Socket() //通过系统默认类型的 SocketImpl 创建未连接套接字

       Socket(InetAddress address, int port)//创建一个流套接字并将其连接到指定 IP 地址的指定端口号。

       Socket(String host, int port) //创建一个流套接字并将其连接到指定主机上的指定端口号。

B、方法摘要:

       void close() //关闭此套接字。

       InetAddress getInetAddress() ///返回套接字连接的地址。

       InputStream getInputStream() //返回此套接字的输入流。

       OutputStream getOutputStream() //返回此套接字的输出流。

       int getPort() //返回此套接字连接到的远程端口。

       void shutdownInput() //此套接字的输入流置于“流的末尾”。

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

       String toString() //将此套接字转换为 String。

(2)ServerSocket

A、构造方法:

       ServerSocket() //创建非绑定服务器套接字。

       ServerSocket(int port) //创建绑定到特定端口的服务器套接字。

B、方法摘要:

       Socket accept() //侦听并接受到此套接字的连接。

       void close() //关闭此套接字。

       InetAddress getInetAddress() //返回此服务器套接字的本地地址。

(3)TCP传输流程:

   客户端:

       建立Socket服务,并制定要连接的主机和端口;

       获取Socket流中的输出流OutputStream,将数据写入流中,通过网络发送给服务端;

       获取Socket流中的输出流InputStream,获取服务端的反馈信息;

       关闭资源。

   服务端:

       建立ServerSocket服务,并监听一个端口;

       通过ServerSocket服务的accept方法,获取Socket服务对象;

       使用客户端对象的读取流获取客户端发送过来的数据;

       通过客户端对象的写入流反馈信息给客户端;

       关闭资源;

(4)典型例题:

例1:客户端

package net;import java.io.BufferedReader;import java.io.BufferedWriter;import java.io.InputStreamReader;import java.io.OutputStreamWriter;import java.io.PrintWriter;import java.net.Socket;public class TcpClient2{/** * 需求:从键盘录入数据,通过Tcp协议向服务端发送,服务端接收到后将数据转换成大写字母,然后返回给用户。 * 数据可以实现不断录入、当遇到指定over字符的时候停止。 *  * @param args */public static void main(String[] args) throws Exception{ // 新建一个客户端套接字服务,同时指定目的IP与接收端口Socket socket = new Socket("192.168.0.104", 10004);// 新建一个键盘的录入的缓冲区BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));// 定义一个套接字通信的输入流的缓冲区PrintWriter printWriter=new PrintWriter(socket.getOutputStream(),true);BufferedReader bufr1 = new BufferedReader(new InputStreamReader(socket.getInputStream()));// 定义一个套接字通信的输出流的缓冲区//BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));String str;// 实现从键盘读取数据然后向套接字通信的输出流输出while ((str = bufr.readLine()) != null){printWriter.println(str);//bufw.write(str);//bufw.newLine();// 向Socket通信的输出流中输入一个换行标记//bufw.flush();// 刷新缓冲区//1、会不会数据还没有返回就已经执行ufr1.readLine(),然后输出的结果为空?String msg = bufr1.readLine();//A、从服务端读取数据System.out.println("Client=" + msg);//B、打印输出的结果}/* * 2、把 A、B出的代码注释掉、换成如下代码为什么没结果? *  * String str1; while ((str1 = bufr1.readLine()) != null) { * System.out.println(str1); } */bufr.close();socket.close();}}


 

服务端:

package net;import java.io.BufferedReader;import java.io.BufferedWriter;import java.io.InputStreamReader;import java.io.OutputStreamWriter;import java.io.PrintWriter;import java.net.ServerSocket;import java.net.Socket;public class TcpServer2{/** * @param args */public static void main(String[] args) throws Exception{// 建立服务套接字,同时指定监听的端口ServerSocket ss = new ServerSocket(10004);// 获取客户端的套接字Socket s = ss.accept();// 打印服务端的IPSystem.out.println("serverprot----" + s.getInetAddress().getHostAddress());// 定义一个套接字通信的输入流的缓冲区BufferedReader bufr = new BufferedReader(new InputStreamReader(s.getInputStream()));// 定义一个套接字通信的输出流的缓冲区PrintWriter printWriter = new PrintWriter(s.getOutputStream(), true);// BufferedWriter bufw = new BufferedWriter(new// OutputStreamWriter(s.getOutputStream()));String str1;while ((str1 = bufr.readLine()) != null)// 从输入缓冲区中读取数据,然后将其转换为大写字母{System.out.println("Server端接收的数据=" + str1);printWriter.println(str1.toUpperCase());// bufw.write(str1.toUpperCase());// bufw.newLine();// bufw.flush();// 刷新缓冲区// bufw.close();}s.close();// 关闭套接字,因为套接字与输入、输出流相关。只要关闭套接字。就不需要在关闭输入、输出流ss.close();// 关闭服务端端套接字}}


 

例2、客户端:

package net;import java.io.*;import java.net.*;class PicClient1{/*客户端。1,定义服务端点。2,读取客户端已有的图片数据。3,通过socket 输出流将数据发给服务端。4,读取服务端反馈信息。5,关闭。*/public static void main(String[] args) throws Exception{Socket s = new Socket("192.168.0.104", 10007);FileInputStream fis = new FileInputStream("E:\\1.jpg");OutputStream out = s.getOutputStream();byte[] buf = new byte[1024];int len = 0;while ((len = fis.read(buf)) != -1){out.write(buf, 0, len);}// 告诉服务端数据已写完s.shutdownOutput();InputStream in = s.getInputStream();byte[] bufIn = new byte[1024];int num = in.read(bufIn);System.out.println(new String(bufIn, 0, num));fis.close();s.close();}}

服务端:


 

package net;import java.io.File;import java.io.FileOutputStream;import java.io.InputStream;import java.io.OutputStream;import java.net.ServerSocket;import java.net.Socket;class PicThread implements Runnable{/*/*服务端这个服务端有个局限性。当A客户端连接上以后。被服务端获取到。服务端执行具体流程。这时B客户端连接,只有等待。因为服务端还没有处理完A客户端的请求,还有循环回来执行下次accept方法。所以暂时获取不到B客户端对象。那么为了可以让多个客户端同时并发访问服务端。那么服务端最好就是将每个客户端封装到一个单独的线程中,这样,就可以同时处理多个客户端请求。如何定义线程呢?只要明确了每一个客户端要在服务端执行的代码即可。将该代码存入run方法中。*/*/private Socket s;PicThread(Socket s){this.s = s;}public void run(){int count = 1;String ip = s.getInetAddress().getHostAddress();try{System.out.println(ip + "....connected");InputStream in = s.getInputStream();// File dir = new File("d:\\pic");File file = new File("D:\\" + ip + "(" + (count) + ")" + ".jpg");while (file.exists())file = new File("D:\\" + ip + "(" + (count++) + ")" + ".jpg");FileOutputStream fos = new FileOutputStream(file);byte[] buf = new byte[1024];int len = 0;while ((len = in.read(buf)) != -1){fos.write(buf, 0, len);}OutputStream out = s.getOutputStream();out.write("上传成功".getBytes());fos.close();s.close();} catch (Exception e){throw new RuntimeException(ip + "上传失败");}}}class PicServer1{public static void main(String[] args) throws Exception{ServerSocket ss = new ServerSocket(10007);while (true){Socket s = ss.accept();new Thread(new PicThread(s)).start();}// ss.close();}}  


 

6、URL的总结:

(1)概述:

URL(Uniform Resource Locator)称为统一资源定位器,它是指向互联网“资源的指针”。资源可以是简单的文件或目录,也可以是对更为复杂对象的引用。JDK中还提供了一个URI(Uniform Resource Identifiers)类们其实例代表一个统一资源标识符,Java的URI不能用于定位任何资源,它的唯一作用就是解析。URL则包含一个可打开到达该资源的输入流,我们可以将URL理解成URI的特例。

URL对象的常用方法:

String getFile():获取该URL的资源名

String getHost():获取该URL的主机名

String getPath():获取该URL的路径部分

int getPort();获取该URL的端口号

String getProtocol():获取该URL的协议名称

String getQuery():获取该URL的查询字符串部分。

URLConnection openConnection()返回一个URLConnection对象,他代表了与URL所引用的远程对象的连接。

InputStream openStream():打开与此URL的连接,并返回一个用于读取该URL资源的InputStream

-------android培训、java培训、期待与您交流!-------

 

原创粉丝点击