------- android培训、java培训、期待与您交流! ----------
网络编程(上)
一、网络编程
1、 网络模型
OSI 参考模型
TCP/IP 参考模型
2、网络通讯要素IP 地址
端口号传输协议
二、网络参考模型
三、网络通讯要素
IP地址: InetAddress
网络中设备的标识
不易记忆,可用主机名
本地回环地址: 127.0.0.1 主机名: localhost
![]()
端口号用于标识进程的逻辑地址,不同进程的标识有效端口:0~65535,其中0~1024系统使用或保留端口。
传输协议通讯的规则常见协议:TCP,UDP
四、TCP和UDP 【重要】
1、 UDP
将数据及源和目的封装成数据包中, 不需要建立连接
每个数据报的大小在限制在 64k 内
因无连接,是不可靠协议
不需要建立连接,速度快
2、TCP
建立连接 ,形成传输数据的通道。
在连接中进行大数据量传输
通过三次握手完成连接,是可靠协议
必须建立连接,效率会稍低
五、Socket
1、有关 Socket
1 ) Socket 就是为网络服务提供的一种机制。
2 ) 通信的两端都有 Socket 。
3 ) 网络通信其实就是 Socket 间的通信。
4 ) 数据在两个 Socket 间通过 IO 传输。
注意: Socket 可以理解为码头,有码头才有船可以对货(数据)进行装卸(读写)。
但是由于船运输的方式不同,所以有了不同的服务方式。一个是 UDP ,另外一个是 TCP 。
2 、重要的类
1)public class DatagramSocketextends Object
此类表示用来发送和接收数据报包的套接字。2)public final class DatagramPacketextends Object
此类表示数据报包。3) public class InetAddressextends Object
implements Serializable
此类表示互联网协议 (IP) 地址。3、小知识192.168.1.254192.168.1.0 这是这个段里边的网络地址
192.168.1.255 这是 192.168.1 这个段里边的广播地址
3 、 Socket 编程
1 )示例:
需求:通过 udp 传输方式,将一段文字数据发送出去。,
定义一个 udp 发送端。
思路:
1,建立updsocket服务。
2,提供数据,并将数据封装到数据包中。
3,通过socket服务的发送功能,将数据包发出去。
4 ,关闭资源。
import java.net.*;class UdpSend{public static void main(String[] args) throws Exception{//1 ,创建 udp 服务。通过 DatagramSocket 对象。
DatagramSocket ds = new DatagramSocket(8888); // 发送端可以使用默认端口。。。
//2 ,确定数据,并封装成数据包。 DatagramPacket(byte[] buf, int length, InetAddress address, int port)
byte[] buf = "udp ge men lai le ".getBytes();DatagramPacket dp =new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.1.254"),10000);//3 ,通过 socket 服务,将已有的数据包发送出去。通过 send 方法。
ds.send(dp);//4 ,关闭资源。
ds.close();}}
/*
需求:
定义一个应用程序,用于接收 udp 协议传输的数据并处理的。
定义 udp 的接收端。
思路:
1,定义udpsocket服务。通常会监听一个端口。其实就是给这个接收网络应用程序定义数字标识。
方便于明确哪些数据过来该应用程序可以处理。
2,定义一个数据包,因为要存储接收到的字节数据。
因为数据包对象中有更多功能可以提取字节数据中的不同数据信息。
3,通过socket服务的receive方法将收到的数据存入已定义好的数据包中。
4,通过数据包对象的特有功能。将这些不同的数据取出。打印在控制台上。
5 ,关闭资源。
*/class UdpRece{public static void main(String[] args) throws Exception{//1, 创建 udp socket ,建立端点。
DatagramSocket ds = new DatagramSocket(10000);while(true){//2, 定义数据包。用于存储数据。
byte[] buf = new byte[1024];DatagramPacket dp = new DatagramPacket(buf,buf.length);//3 ,通过服务的 receive 方法将收到数据存入数据包中。
ds.receive(dp);// 阻塞式方法。//4 ,通过数据包的方法获取其中的数据。
String ip = dp.getAddress().getHostAddress();String data = new String(dp.getData(),0,dp.getLength());int port = dp.getPort();System.out.println(ip+"::"+data+"::"+port);}//5 ,关闭资源
//ds.close(); // 第二部来的 ,互动 使接收端一直开着。。
}}
2) 示例----------------必须掌握!!!
编写一个聊天程序。有收数据的部分,和发数据的部分。这两部分需要同时执行。那就需要用到多线程技术。一个线程控制收,一个线程控制发。因为收和发动作是不一致的,所以要定义两个 run 方法。
而且这两个方法要封装到不同的类中。import java.io.*;import java.net.*;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){byte[] buf = line.getBytes();DatagramPacket dp =new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.1.255"),10002);ds.send(dp);if("886".equals(line))break;}}catch (Exception e){throw new RuntimeException(" 发送端失败 ");
}}}class Rece implements Runnable{private DatagramSocket ds;public Rece(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());if("886".equals(data)){System.out.println(ip+".... 离开聊天室 ");
break;}System.out.println(ip+":"+data);}}catch (Exception e){throw new RuntimeException(" 接收端失败 ");
}}}class ChatDemo{public static void main(String[] args) throws Exception{DatagramSocket sendSocket = new DatagramSocket();DatagramSocket receSocket = new DatagramSocket(10002);new Thread(new Send(sendSocket)).start();new Thread(new Rece(receSocket)).start();}}
3) 示例
/*
演示 tcp 传输。
1,tcp 分客户端和服务端。
2 ,客户端对应的对象是 Socket 。
服务端对应的对象是 ServerSocket 。
客户端,通过查阅 socket 对象,发现在该对象建立时,就可以去连接指定主机。
因为 tcp 是面向连接的。所以在建立 socket 服务时,
就要有服务端存在,并连接成功。形成通路后,在该通道进行数据的传输。需求:给服务端发送给一个文本数据。步骤:1 ,创建 Socket 服务。并指定要连接的主机和端口。
*/import java.io.*;import java.net.*;class TcpClient{public static void main(String[] args) throws Exception{// 创建客户端的 socket 服务。指定目的主机和端口
Socket s = new Socket("192.168.1.254",10003);// 为了发送数据,应该获取 socket 流中的输出流。
OutputStream out = s.getOutputStream();out.write("tcp ge men lai le ".getBytes());s.close(); // 流就不用关了,因为是随着 socket 来的
}}/*需求:定义端点接收数据并打印在控制台上。服务端 :
1 ,建立服务端的 socket 服务。 ServerSocket();
并监听一个端口。2 ,获取连接过来的客户端对象。
通过 ServerSokcet 的 accept 方法。没有连接就会等,所以这个方法阻塞式的。
3 ,客户端如果发过来数据,那么服务端要使用对应的客户端对象,并获取到该客户端对象的读取流来读取发过来的数据。
并打印在控制台。4 ,关闭服务端。(可选)
*/class TcpServer{public static void main(String[] args) throws Exception{// 建立服务端 socket 服务。并监听一个端口。
ServerSocket ss = new ServerSocket(10003);// 通过 accept 方法获取连接过来的客户端对象。
while(true){Socket s = ss.accept();String ip = s.getInetAddress().getHostAddress();System.out.println(ip+".....connected");// 获取客户端发送过来的数据,那么要使用客户端对象的读取流来读取数据。
InputStream in = s.getInputStream();byte[] buf = new byte[1024];int len = in.read(buf);System.out.println(new String(buf,0,len));s.close();// 关闭客户端 .
}//ss.close();}}
4 )、示例
需求:建立一个文本转换服务器。
客户端给服务端发送文本,服务单会将文本转成大写在返回给客户端。
而且客户度可以不断的进行文本转换。当客户端输入 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.254",10005);// 定义读取键盘数据的流对象。
BufferedReader bufr =new BufferedReader(new InputStreamReader(System.in));// 定义目的,将数据写入到 socket 输出流。发给服务端。
//BufferedWriter bufOut =//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);// bufOut.write(line);// bufOut.newLine();// bufOut.flush();String str =bufIn.readLine();System.out.println("server:"+str);}bufr.close();s.close();}}/*服务端:源: socket 读取流。
目的: socket 输出流。
都是文本,装饰。*/class TransServer{public static void main(String[] args) throws Exception{ServerSocket ss = new ServerSocket(10005);Socket s = ss.accept();String ip = s.getInetAddress().getHostAddress();System.out.println(ip+"....connected");// 读取 socket 读取流中的数据。
BufferedReader bufIn =new BufferedReader(new InputStreamReader(s.getInputStream()));// 目的。 socket 输出流。将大写数据写入到 socket 输出流,并发送给客户端。
//BufferedWriter bufOut =//new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));PrintWriter out = new PrintWriter(s.getOutputStream(),true);String line = null;while((line=bufIn.readLine())!=null){System.out.println(line);out.println(line.toUpperCase());}s.close();ss.close();}}/*该例子出现的问题。现象:客户端和服务端都在莫名的等待。为什么呢?因为客户端和服务端都有阻塞式方法。这些方法么没有读到结束标记。那么就一直等而导致两端,都在等待。((line=bufIn.readLine())!=null)readLine 方法是阻塞式方法,必须碰到回车符才会判断读取一行完毕,返回数据,否则会一直在读
所以加 bu fOut.newLine();---- 》自动换行
*/