一、网络编程概述
- 定义
- 计算机网络
- 是指将地理位置不同的具有独立功能的多台计算机以及外部设备,通过通信线路连接起来,在网络操作系统,网络管理软件以及网络通信协议的管理和协调下,实现资源共享和信息传递的计算机系统
- 网络编程
- 用来实现网络互连的不同计算机上运行的程序间,可以进行数据交换
- 计算机网络
- IP地址
- 每个设备在网络中的唯一标识
- 每台网络终端在网络中都有一个独立的地址,我们在网络中传输数据就是使用这个地址
- ipconfig:查看本机IP
- ping:测试连接
- 本地回路地址:127.0.0.1
- IPv4:4个字节组成,4个0-255。大概42亿个,30亿都在北美,亚洲4亿。2011年初已经用完
- IPv6:8组,每组4个16进制数
- 端口号
- 每个程序在设备上的唯一标识
- 每个网络程序都需要绑定一个端口号,传输数据的时候除了确定发到哪台机器上,还要明确发到哪个程序
- 端口号范围从0-65535
- 编写网络应用就需要绑定一个端口号,尽量使用1024以上的,1024以上的基本上都被系统程序占用了
- 协议
- 为计算机网络中进行数据交换而建立的规则、标准、或约定的集合
- UDP
- 面向无连接,数据不安全,速度快。不区分客户端和服务端
- TCP
- 面向连接(三次握手),数据安全,速度略低。分为客户端和服务端
- 三次握手:客户端先向服务端发起请求,服务端响应请求,客户端发送确认信息
二、Socket通信
- 定义
- 网络上具有唯一标识的IP地址和端口号组合在一起才能构成唯一能够识别的标识符套接字
- 通信的两端都有Socket
- 网络的两端都有Socket
- 网络通信其实就是Socket间的通信
- 数据在两个Socket间通过IO流传输
- Socket在应用程序中创建,通过一种绑定机制与驱动程序建立关系,告诉自己所对应的IP和port(端口)
三、UDP传输
-
发送Send
- 创建DatagramSocket,指定端口号
- 创建DatagramPacket,指定数据,长度,地址,端口
- 使用DatagramSocket发送DatagramPacket
- 关闭DatagramSocket
-
接收Receive
- 创建DatagramSocket,指定端口号
- 创建DatagramPacket,指定数据,长度
- 使用DatagramSocket接收DatagramPacket
- 关闭DatagramSocket
- 从DatagramPacket中获取数据
-
接收方式获取ip和端口号
- String ip = packet.getAddress().getHostAddress();
- int port = packet.getPort();
-
演示
-
发送端
public static void main(String[] args) throws Exception { //确定要发送的内容 String str = "你愿意跟我一起去吃麻辣烫吗?"; //创建发送端Socket 可以ip ,会提供一个随机的 DatagramSocket socket = new DatagramSocket(); //创建装载数据的包 要指明IP地址,端口号, DatagramPacket packet = new DatagramPacket(str.getBytes(), str.getBytes().length, InetAddress.getByName("127.0.0.1"), 6666); //发送数据 socket.send(packet); //关闭socket socket.close(); }
-
接收端
public static void main(String[] args) throws Exception { //创建接收端Socket,必须指定端口,不然接收不到 DatagramSocket socket = new DatagramSocket(6666); //创建装载数据的包 DatagramPacket packet = new DatagramPacket(new byte[1024], 1024); //接收数据, 阻塞方法 socket.receive(packet); //获取接收到的数据 byte[] bs = packet.getData(); //获取接收到的有效数据的长度 int len = packet.getLength(); System.out.println(new String(bs,0,len)); //获取对方法的端口号 System.out.println(packet.getPort()); //获取对方的ip地址 System.out.println(packet.getAddress()); //关闭socket socket.close(); }
-
-
UDP传输优化
public static void main(String[] args) throws Exception { //从键盘录入数据 BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); //创建发送端Socket DatagramSocket socket = new DatagramSocket(); //循环接收数据 while(true){ String str = br.readLine(); //创建装载数据的包 要指明IP地址,端口号, DatagramPacket packet = new DatagramPacket(str.getBytes(), str.getBytes().length, InetAddress.getByName("127.0.0.1"), 6666); //发送数据 socket.send(packet); if("结束".equals(str)){ break; } } //关闭socket socket.close(); }
四、UDP传输之多线程
-
定义
- 使用多线程同时启动接收端和发送端
-
演示
-
发送端
class Send extends Thread { public void run() { DatagramSocket socket = null; BufferedReader br = null; try { socket = new DatagramSocket(); //创建socket相当于创建码头 br = new BufferedReader(new InputStreamReader(System.in)); while(true) { String str = br.readLine(); if("quit".equals(str)) break; DatagramPacket packet = //创建packet相当于创建集装箱 new DatagramPacket(str.getBytes(), str.getBytes().length, InetAddress.getByName("127.0.0.1"), 6666); socket.send(packet); //发货 } socket.close(); } catch (IOException e) { e.printStackTrace(); }finally { try { socket.close(); br.close(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
-
接收端
class Receive1 extends Thread { public void run() { DatagramSocket socket = null; DatagramPacket packet = null; try { socket = new DatagramSocket(6666); //创建socket相当于创建码头 packet = new DatagramPacket(new byte[1024], 1024);//创建packet相当于创建集装箱 while(true) { socket.receive(packet); //接收货物 byte[] arr = packet.getData(); int len = packet.getLength(); String ip = packet.getAddress().getHostAddress(); System.out.println(ip + ":" + new String(arr,0,len)); } } catch (IOException e) { e.printStackTrace(); }finally { socket.close(); } } }
-
启动
public static void main(String[] args) { new Receive1().start(); new Send1().start(); }
-
五、TCP协议
-
定义
- 客户端和服务器间的交流,客户端发送信息,服务器接收到并返回信息
- 长连接
-
使用步骤
客户端
- 创建Socket连接服务器(指定ip地址,端口号)通过ip地址找对应的服务器
- 调用Socket的getInputStream()和getOutputStream()方法获取和服务器相连的IO流
- 客户端输入流可以读取服务器端输出流写出的数据
- 客户端输出流可以写出数据到服务端的输入流
服务端
- 创建ServerSocket(需要指定接口号)
- 调用ServerSocket的accept()方法接收一个客户端请求,得到一个Socket
- 调用Socket的getInputStream()和getOutputSream()方法获取和客户端相连的IO流
- 服务端输入流可以读取客户端输出流写出的数据
- 服务器输出流可以写出数据到客户端的输入流
-
演示
-
客户端
public static void main(String[] args) throws Exception { Socket socket = new Socket("127.0.0.1", 6666); //发送信息 OutputStream stream = socket.getOutputStream(); String str = "我很中意你呀"; stream.write(str.getBytes()); //接收返回的信息 InputStream is = socket.getInputStream(); byte[] bs = new byte[1024]; int len ; len=is.read(bs); System.out.println(new String(bs,0,len)); socket.close(); }
-
服务端
public static void main(String[] args) throws Exception { ServerSocket server = new ServerSocket(6666); Socket socket = server.accept(); //接收信息 InputStream is = socket.getInputStream(); byte[] bs = new byte[1024]; int len ; len = is.read(bs); System.out.println(new String(bs,0,len)); //返回信息 OutputStream stream = socket.getOutputStream(); String str = "哎呀, 知道了"; stream.write(str.getBytes()); socket.close(); }
-
-
TCP传输优化
-
客户端
public static void main(String[] args) throws Exception { Socket socket = new Socket("127.0.0.1", 6666); //接收信息 InputStream is = socket.getInputStream(); BufferedReader br = new BufferedReader(new InputStreamReader(is)); //发送信息 OutputStream stream = socket.getOutputStream(); BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(stream)); BufferedReader sca = new BufferedReader(new InputStreamReader(System.in)); String str; while(true){ str = sca.readLine(); if ("结束".equals(str)) { break; } bw.write(str); bw.newLine(); bw.flush(); //接收返回的信息 str = br.readLine(); System.out.println(str); } socket.close(); }
-
服务端
public static void main(String[] args) throws Exception { ServerSocket server = new ServerSocket(6666); Socket socket = server.accept(); //接收信息 InputStream is = socket.getInputStream(); BufferedReader br = new BufferedReader(new InputStreamReader(is)); //发送信息 OutputStream stream = socket.getOutputStream(); BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(stream)); BufferedReader sca = new BufferedReader(new InputStreamReader(System.in)); String str ; while(true){ str = br.readLine(); System.out.println(str); str = sca.readLine(); if("结束".equals(str)) break; bw.write(str); bw.newLine(); bw.flush(); } socket.close(); }
-
六、多线程服务器
-
定义
- 每当一个请求过来,服务器就会产生一个Socket连接,为了避免前面的socket阻碍后面的socket运行,我们必须创建一个新的线程来发送请求
-
演示
public static void main(String[] args) throws Exception { ServerSocket server = new ServerSocket(9999); //创建服务器 while(true) { Socket socket = server.accept(); //接受客户端的请求 //创建一个线程来处理请求 new Thread() { public void run() { try { BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); PrintStream ps = new PrintStream(socket.getOutputStream()); ps.println("欢迎咨询千锋互联"); System.out.println(br.readLine()); ps.println("报满了,请报下一期吧"); System.out.println(br.readLine()); socket.close(); } catch (IOException e) { e.printStackTrace(); } } }.start(); } }
七、文件上传
-
定义
- 其实就是通过流从本地文件中读取数据,通过网络传输到服务器
- 服务器在接收到数据之后再存储到本地
-
演示
-
客户端
public static void main(String[] args) throws Exception { //1.和服务器建立连接 Socket socket = new Socket("127.0.0.1", 9999); //2.获取输出流,往服务器写数据 //BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); OutputStream os = socket.getOutputStream(); //3.获取输入流,获取服务器发送过来的数据 BufferedReader br = new BufferedReader(new InputStreamReader( socket.getInputStream())); FileInputStream fis = new FileInputStream("d:\\骑在银龙的背上.mp3"); byte[] bs = new byte[1024]; int len ; while ((len=fis.read(bs))!=-1) { os.write(bs, 0, len); } socket.shutdownOutputStream(); String str = br.readLine(); if("200".equals(str)) System.out.println("文件上传成功"); else System.out.println("文件上传失败"); socket.close(); }
-
服务端
public static void main(String[] args) throws Exception { //服务端必须先启动 ServerSocket serverSocket = new ServerSocket(9999); //1.和客户端建立连接(被动) Socket socket = serverSocket.accept(); //2.获取输入流,获取从客户端发送过来的数据 InputStream is = socket.getInputStream(); //3.获取输出流,往客户端写数据 BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); FileOutputStream fos = new FileOutputStream("d:\\音乐.mp3"); byte[] bs = new byte[1024]; int i ; while((i=is.read(bs))!=-1){ fos.write(bs,0,i); } //写一个200回去表示成功 bw.write("200"); bw.newLine(); bw.flush(); fos.close(); socket.close(); }
-
总结
- 网络传输的概述
- ip:通过ip可以找到找到网络中的一台机器
- port:通过端口号可以找到电脑中某个程序
- ip+port:一个套接字
- UDP:快,不安全,面向无连接
- TCP:慢,安全,面向有连接
- UDP编码
- DatagramSocket
- DatagramPacket
- DatagramPacket包裹着ip地址,端口号,数据
- DatagramSocket发送包裹
- 接收端和发送端是平等的
- TCP编码
- Socket
- ServerSocket
- ServerSocket可以接收多个Socket,每接收一个客户端连接,就会创建一个Socket与客户端通信
- TCP的最大优点:两端是由一个通道连接,可以随意传输数据,不会受到数据量大小的限制
- 服务端一般与多线程配合使用
- 查阅资料:思考TCP传输的缺点和解决办法?
作业
- 编程模拟文件的下载
- 从键盘录入地址,通过网络传输复制文件