第一讲 网络概述
1、网络通信三要素:电脑IP地址、软件本地端口号、网络间传输协议(国际通用的TIP/IP,还有很多其他的)
小知识:-ping 127.0.0.7可以测试网卡用
2、网络模型图列:
用户在运用层发出的数据,经过逐层打包后通过物理层传输到另一个模型中,然后逐层分解,找到端口,被另一个用户获得
IP地址:InetAddress
• 网络中设备的标识
• 不易记忆,可用主机名
• 本地回环地址:127.0.0.1 主机名:localhost
使用java.net包中的InetAddress,注意没有构造函数不需要new
InetAddress类
(1)无构造函数:如 InetAddress i=InetAddress.getLocalHost();得到本机的InetAddress
InetAddress i=InetAddress.getgetByName("195.115.1.65");得到某IP或名称的InetAddress
(2) 方法:static InetAddress getByName(String host);获得指定主机的InetAddress,最好用Ip
static InetAddress[] getByName(String host);在给定主机名的情况下,根据系统上配置的名称返回数组
String getHostAddresss()和String getHostName():如名字
(3)获得
1 import java.net.*; 2 3 public class IPdemo { 4 public static void main(String[] args)throws Exception{ 5 // 获取本机 6 InetAddress i = InetAddress.getLocalHost(); 7 System.out.println(i.toString()); 8 System.out.println(i.getHostAddress()); System.out.println(i.getHostName()); 9 // 获取百度 10 InetAddress[] baidu=InetAddress.getAllByName("www.google.com"); 11 for(InetAddress b:baidu){ 12 String ss=b.getHostAddress(); 13 String bb=b.getHostName(); 14 System.out.println(ss+"::"+bb); 15 } 16 17 } 18 }
端口号
• 用于标识进程的逻辑地址,不同进程的标识
• 有效端口:0~65535,其中0~1024系统使用或保留端口。
传输协议
• 通讯的规则
• 常见协议:TCP,UDP
UDP
• 将数据及源和目的封装成数据包中,不需要建立连接
• 每个数据报的大小在限制在64k内
• 因无连接,是不可靠协议
• 不需要建立连接,速度快
如:网络视频、qq等
TCP
• 建立连接,形成传输数据的通道。
• 在连接中进行大数据量传输
• 通过三次握手完成连接,是可靠协议
• 必须建立连接,效率会稍低
如:下载、迅雷
第二讲 传输协议
1.Socket
Socket中文名插座,是为网络服务提供的一种机制。
通信的两端都有Socket,才能连接
网络通信其实就是Socket间的通信,数据在两个Socket间通过IO传输。
UDP协议
以下是UDP传输实例:
发送端:
1 /* 2 * 需要通过udp发送,并通过udp接受后打印 3 */ 4 import java.net.*; 5 public class UDPSend { 6 public static void main(String[] args)throws Exception{ 7 // 建立UDPSovket 8 DatagramSocket ds=new DatagramSocket(888);//建立一个发送端,括号未填时主机分配 9 // 确定数据,搞一个数据包,DatagramPacket(byte[],int,InetAddress,端口) 10 byte[] buf="lalala lal lal ala".getBytes(); 11 DatagramPacket dp = 12 new DatagramPacket(buf, buf.length, 13 InetAddress.getByName("192.168.5.159"),500); 14 // 发送到发数据啊 15 ds.send(dp); 16 17 ds.close(); 18 } 19 }
接收端
1 import java.net.InetAddress; 2 3 //接收端 4 public class UDPre { 5 public static void main(String[] args)throws Exception{ 6 7 // 建立UDPSovket接受用 8 DatagramSocket ds=new DatagramSocket(500);//括号未填时主机分配 while(true){ 9 // 定义数据包用于存储数据 10 byte[] buf=new byte[1024]; 11 DatagramPacket dp = 12 new DatagramPacket(buf,buf.length); 13 // 接收数据并存在dp中 14 ds.receive(dp); 15 //解析数据, 16 String ip=dp.getAddress().getHostName(); 17 String data=new String(dp.getData(),0,dp.getLength());//后两个是接收那个 18 int port=dp.getPort();//发送端的端口 19 20 System.out.println(ip+"**"+data+"++"+port); 21 ds.close(); } 22 } 23 }
使用键盘输入并打印
/* * 需要通过udp发送,并通过udp接受后打印 */ import java.net.*; import java.io.*; class UdpSend { public static void main(String[] args) throws Exception { // 搞一个DatagramSocket为888的端口 DatagramSocket ds = new DatagramSocket(888); // 键盘输入换成读取流 BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in)); String line = null; while((line=bufr.readLine())!=null) { if("over".equals(line)) break; byte[] buf = line.getBytes(); DatagramPacket dp = new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.5.159"),10001); ds.send(dp); } ds.close(); } } class UdpRece { public static void main(String[] args) throws Exception { DatagramSocket ds = new DatagramSocket(10001); while(true) { // 做一个数据包 byte[] buf = new byte[1024]; DatagramPacket dp = new DatagramPacket(buf,buf.length); ds.receive(dp); //从数据包里读取ip和data String ip = dp.getAddress().getHostAddress(); String data = new String(dp.getData(),0,dp.getLength()); System.out.println(ip+"::"+data); } } }
注“192.168.1.255是公共的平台,是发给所有人的,只要端口对了。
1 /*编写一个聊天程序 2 * 发送和接收数据的部分需要同时执行, 3 * 所以要多线程计算 4 * 5 * 所以发送和接收定义为两个类并实现Runnable,自定义run 6 * 而且这两个方法封装在不同的类中send,rec; 7 */ 8 import java.io.*; 9 import java.net.*; 10 //发送端 11 class Send implements Runnable 12 { 13 // Socket端为构造函数 14 private DatagramSocket ds; 15 Send(DatagramSocket ds){ 16 this.ds=ds; 17 } 18 // 复写run 19 public void run(){ 20 // 使用try~~catch发送 21 try { 22 DatagramPacket dp=null; 23 BufferedReader br= 24 new BufferedReader(new InputStreamReader(System.in)); 25 String line=null; 26 while((line=br.readLine())!=null){ 27 // 数据包 28 byte[] buf=line.getBytes(); 29 dp=new DatagramPacket 30 (buf,buf.length,InetAddress.getByName("192.168.1.255"),1000); 31 ds.send(dp); 32 if(line.equals("over")){ 33 break; 34 } 35 } 36 br.close(); 37 } catch (Exception e) { 38 throw new RuntimeException("发送失败啦"); 39 } 40 } 41 } 42 43 //接收端 44 class Rec implements Runnable 45 { 46 private DatagramSocket ds; 47 Rec(DatagramSocket ds){ 48 this.ds=ds; 49 } 50 51 // 复写run 52 public void run(){ 53 // 死循环让其一直处于接收状 54 try { 55 while(true){ 56 // 数据包 57 byte[] buf=new byte[1024]; 58 DatagramPacket dp= 59 new DatagramPacket(buf, buf.length); 60 ds.receive(dp); 61 // 获得数据 62 String ip=dp.getAddress().getHostAddress(); 63 String data=new String(dp.getData(),0,dp.getLength()); 64 65 System.out.println(ip+":"+data); 66 } 67 } catch (Exception e) { 68 throw new RuntimeException("接收端失败"); 69 } 70 } 71 } 72 73 public class UdpChatDemo { 74 75 public static void main(String[] args)throws Exception{ 76 Send send=new Send(new DatagramSocket());//发送端发出1000 77 Rec rec=new Rec(new DatagramSocket(1000)); 78 79 new Thread(send).start(); 80 new Thread(rec).start(); 81 } 82 83 }
三、TCP传输
1、TCP分为:客户端对象Socket和客户服务端ServerSocket
2、方法:
1)创建Socket():空参数一般用于服务端接受数据
Socket(String host,int port):指定接受的IP和端口
2)创键ServerSocket(int port):指定接受客户端的端口
3)Socket accept();监听并接收此套接字的连接
4)void shutdownInput();此套接字的输入流置于流的末端
5)void shutdownOutput();禁止此套接字的输出流
6)InputStream getInputStream();返回此套接字的输出流
7)OutpurStream getOutputStream();返回套接字的输出流,socket对象调用
3、基本思路:
客户端:
1)客户端明确服务端的IP和端口,试着连接,如果失败则报异常
2)连接成功,说客户端与服务端建立通道,那么通过IO流进行数据传输,可getInputStream(),getOutputStream()获取
3)与服务端通讯接受,关闭Socket
服务端:
1)服务端需要明确它要处理的数据从哪个端口进入;
2)当有客户端访问时,要明确哪个客户端,可通过accept()获取已连接客户端对象,并通过该对象鱼客户端通过IO进行数据传输
3)当该客户端访问接受,关闭客户端;
栗子:
该栗子在执行过程中,会出现客户端和服务端莫名的等待——这是由于都有阻塞式的方法
read和write,他们没有读到结束标记(换行)时,会阻塞。所以又加上bufOut.newLine()
bufOut.flush();
在以后开发过程中遇到此类莫名等待的问题时都应该查找阻塞式的方法的API
1 import java .io.*; 2 import java .net.*; 3 4 class TranCient{ 5 6 public static void main(String[] args)throws Exception{ 7 8 Socket s=new Socket("192.168.5.159",8888); 9 10 // 键盘输出并被读取,继而发到输出流所以又BufferedReader和BuffereWriter 11 BufferedReader bufr= 12 new BufferedReader(new InputStreamReader(System.in)); 13 // 用于将数据絮儿socket 14 BufferedWriter bufout= 15 new BufferedWriter(new OutputStreamWriter(s.getOutputStream())); 16 17 // 定义读取流用于读取客户端的信息 18 BufferedReader bufin= 19 new BufferedReader(new InputStreamReader(s.getInputStream())); 20 21 // 开始读取写入的数据给客户端 22 String line=null; 23 24 while((line=bufr.readLine())!=null){ 25 bufout.write(line); 26 bufout.newLine(); 27 bufout.flush(); 28 29 if("over".equals(line)) 30 break; 31 } 32 } 33 } 34 35 //客户端 36 class TransServer{ 37 38 public static void main(String[] args)throws Exception{ 39 ServerSocket ss=new ServerSocket(8888); 40 // 客户端接受信息形成一个Socket了 41 Socket s=ss.accept(); 42 String IP=s.getInetAddress().getHostAddress(); 43 System.out.println(IP); 44 // 读取流中的数据 45 BufferedReader bufin= 46 new BufferedReader(new InputStreamReader(s.getInputStream())); 47 // 将数据传出 48 BufferedWriter bufout= 49 new BufferedWriter(new OutputStreamWriter(s.getOutputStream())); 50 // PrintWriter pw=new PrintWriter(s.getOutputStream(),true); 51 // 使用printWrier能自动换行的刷新 52 53 // 开搞,写读,然后大写后输出 54 String line=null; 55 while((line=bufin.readLine())!=null){ 56 System.out.println(line); 57 58 // pw.print(line);使用该方法不需要换行和刷新 59 60 bufout.write(line.toUpperCase()); 61 bufout.newLine(); 62 bufout.flush(); 63 64 } 65 s.close(); 66 ss.close();//选择性关闭 67 68 } 69 }
练习
需求:向服务器上次一个文件,无法企要返回一个信息
一、客户端
有读取流BufferedReader读取硬盘的文件
有printWrite输出文件(读完后需要使用shutdownOutput()表示结束语,服务端才能结束)
还需要BufferedReader读取服务端的数据
二、服务端
需要接受形成socket
打印IP代表连接完成
读取流BufferedReader读取客户端的形象
需要printWrite输出一个文件在服务端
还需要BufferedWriter(使用printWriter也行)把信息传出去
1 /*需求:向服务器上次一个文件,无法企要返回一个信息 2 3 一、客户端 4 5 有读取流BufferedReader读取硬盘的文件 6 7 有printWrite输出文件(读完后需要使用shutdownOutput()表示结束语,服务端才能结束) 8 9 还需要BufferedReader读取服务端的数据 10 11 二、服务端 12 13 需要接受形成socket 14 15 打印IP代表连接完成 16 17 读取流BufferedReader读取客户端的形象 18 19 需要printWrite输出一个文件在服务端 20 21 还需要BufferedWriter(使用printWriter也行)把信息传出去 22 */ 23 import java.io.*; 24 import java.net.*; 25 26 //客户端 27 class TCPclient{ 28 29 public static void main(String[] args)throws Exception{ 30 Socket s=new Socket("192.168.5.159",8888); 31 // 读取硬盘 32 BufferedReader bufr= 33 new BufferedReader(new FileReader("D:\\Demo.java")); 34 // 定义目的,是通过Socket输出去,需要输出流 35 PrintWriter pwOut= 36 new PrintWriter(s.getOutputStream(),true); 37 38 // 读取Socket得到服务端的数据 39 BufferedReader bufIn= 40 new BufferedReader(new InputStreamReader(s.getInputStream())); 41 42 String line=null; 43 while((line=bufr.readLine())!=null){ 44 pwOut.println(line); 45 } 46 s.shutdownInput();//结束标记 47 System.out.println(bufIn.readLine());//返回的信息一般很短 48 // 关闭流 49 bufr.close(); 50 s.close(); 51 } 52 } 53 54 55 //服务端 56 class TCPserver{ 57 58 public static void main(String[] args)throws Exception{ 59 // 创建服务端 60 ServerSocket ss=new ServerSocket(8888); 61 62 Socket s=ss.accept(); 63 64 System.out.println(s.getInetAddress().getHostAddress()+"connected--"); 65 // 读取客户端发来的信息 66 BufferedReader bufr= 67 new BufferedReader(new InputStreamReader(s.getInputStream())); 68 // 把数据写入字节的文件中 69 PrintWriter pwout= 70 new PrintWriter(new FileWriter( "D:\\tt.txt"),true); 71 72 while((line=bufr.readLine())!=null){ 73 pwout.println(line); 74 75 } 76 // 把数据写出去出反馈用 77 PrintWriter pp2= 78 new PrintWriter(s.getOutputStream(),true); 79 String line =null; 80 pp2.println("上床成功"); 81 // 对比一下BufferedWriter上床的方法,还是用PrintWriter省事 82 // BufferedWriter bufOut= 83 // new BufferedWriter(new OutputStreamWriter(s.getOutputStream())); 84 // bufOut.write("上床成功"); 85 // bufOut.newLine(); 86 // bufOut.close(); 87 88 pwout.close(); 89 s.close(); 90 ss.close(); 91 } 92 }