2019-06-05 Java学习日记 day26 网络编程
网络编程
*计算机网络
是指将地理位置不同的具有独立性功能的多台计算机及其外部设备,通过通信线路连接起来,在网络操作系统,网络管理软件及网络通信协议的管理和协调下,实现资源共享和信息传递的计算机系统
*网络编程
就是用来实现网络互连的不同计算机上运行的程序间可以进行数据交换
网络编程三要素
IP
每个设备在网络中的唯一标识
每台网络终端在网络中都有一个独立的地址,我们在网络中传输数据就是使用这个地址
ipconfig:查看本机IP 192.168.12.42
ping:测试连接192.168.40.62
本地回路地址:127.0.0.1 255.25.255.255是广播地址
IPv4:4和字节组成,4个0-255。大概42亿,30亿都在北美,亚洲4亿。2011年初已用尽
Ipv6:8组,魅族4个16进制数
1a2b:0000:aaaa:0000:0000:0000:aabb:1f2f
1a2b::aaaa:0000:0000:0000:aabb:1f2f
1a2b:0000:aaaa::aabb:1f2f
1a2b::0000aaaa::0000:aabb:1f2f
1a2b:0000:aaaa:0000::aabb:1f2f
端口号
每个程序在设备上的唯一标识
每个网络程序都需要绑定一个端口号,传输数据的时候除了确认发到那台机器上,还要明确发到哪个程序
端口号范围从 0-65535
编写网络应用就需要绑定一个端口号,尽量使用1024以上的,1024以下的基本上都被系统程序占用了
常用端口:
myapl:3306
oracle:1521
web:00
tomcat:8080
QQ:4000
feiQ:2425
协议
为计算机网络中进行数据交换为建立的规则,标准或约定的集合
UDP
面向无连接,数据不安全,速度快,不区分客户端与服务端
TCP
面向连接(三次握手),数据安全,速度略低,分为客户端和服务端
三次握手:客户端先向服务端发起请求,服务端响应请求,传输数据
Socket通信原理图解
网络上具有唯一标识的IP地址和端口号组合在一起才能构成唯一识别的标识符套接字
通信的两端都有Socket
网络通信其实就是Socket间的通信
数据在两个Socket间通过IO流传输
Socket在应用程序中创建,通过一种绑定机制与驱动程序建立关系,告诉自己所对应的IP和port
UDP传输
发送Send
创建DataGramSocket,随机端口号
创建DtatgramPacket,指定数据,长度,地址,端口
使用DataGramSocket发送DataGramPacket
关闭DataGramSocket
接受Receive
创建DataGramSocket,指定端口号
创建DataGramPacket,指定数据,长度,地址,端口
使用DataGramSocket接受DataGramPacket
关闭DataGramSocket
从DataGramPacket中获取数据
接受方获取ip和端口号
String ip = packetgetAddress().getHostAddress()
int port = packet.getPort()
UDP多线程
import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.SocketException; import java.net.UnknownHostException; import java.util.Scanner; public class demo3_MoreThread { public static void main(String[] args) { new Receive().start(); new Send().start(); } } class Receive extends Thread{ public void run(){ try { DatagramSocket socket =new DatagramSocket(6666); DatagramPacket packet= new DatagramPacket(new byte[1024], 1024); while(true){ socket.receive(packet); byte [] arr =packet.getData(); //获取数据 int len =packet.getLength(); //获取有效的字节个数 String ip=packet.getAddress().getHostAddress(); //获取ip地址 int port =packet.getPort(); //获取端口号 System.out.println(ip + ":"+port+":"+new String(arr,0,len)); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } class Send extends Thread{ public void run (){ try { Scanner scanner=new Scanner(System.in); DatagramSocket socket =new DatagramSocket(); while(true){ String line =scanner.nextLine(); if ("quit".equals(line)) { break; } DatagramPacket packet = new DatagramPacket( line.getBytes(),line.getBytes().length,InetAddress.getByName("127.0.0.1"),6666); socket.send(packet); } socket.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
UDP聊天图形化
import java.awt.BorderLayout; import java.awt.Button; import java.awt.Color; import java.awt.Event; import java.awt.Font; import java.awt.Frame; import java.awt.Panel; import java.awt.TextArea; import java.awt.TextField; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.BufferedWriter; import java.io.ByteArrayOutputStream; import java.io.FileInputStream; import java.io.FileWriter; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.SocketException; import java.net.UnknownHostException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.logging.Logger; public class demo4_GUIChat extends Frame { private TextField tf; private Button send; private Button log; private Button clear; private Button shake; private TextArea viewText; private TextArea sendText; private DatagramSocket socket; private BufferedWriter bw; public demo4_GUIChat(){ init(); southPanel(); centerPanel(); event(); } private void event() { this.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent arg0) { socket.close(); try { bw.close(); } catch (IOException e) { e.printStackTrace(); } System.exit(0); } }); send.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { try { send(); } catch (IOException e1) { e1.printStackTrace(); } } }); log.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { try { logFile(); } catch (IOException e1) { e1.printStackTrace(); } } }); clear.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { viewText.setText("");//清屏 } }); shake.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { shake(); } }); send.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { try { send(new byte[]{-1},tf.getText()); } catch (IOException e) { e.printStackTrace(); } } }); sendText.addKeyListener(new KeyAdapter() { public void keyReleased(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_ENTER && e.isControlDown()) { try { send(); } catch (IOException e1) { e1.printStackTrace(); } } } }); } private void shake() { int x=this.getLocation().x; //获取横坐标 int y=this.getLocation().y; //获取纵坐标 for(int i= 0; i< 4;i++){ try { this.setLocation(x + 10,y + 10); Thread.sleep(20); this.setLocation(x + 10,y - 10); Thread.sleep(20); this.setLocation(x - 10,y + 10); Thread.sleep(20); this.setLocation(x - 10,y - 10); Thread.sleep(20); this.setLocation(x,y); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } private void logFile() throws IOException { bw.flush();//刷新缓冲区 FileInputStream fis =new FileInputStream("cofing.txt"); ByteArrayOutputStream boas =new ByteArrayOutputStream();//在内存中创建缓冲区 int len; byte [] arr =new byte[8192]; while ((len = fis.read(arr)) != -1) { boas.write(arr,0,len); } String str =boas.toString();//将内存中的内容转换成了字符串 viewText.setText(str); fis.close(); } private void send(byte [] arr,String ip) throws IOException{ DatagramPacket packet =new DatagramPacket( arr, arr.length,InetAddress.getByName(ip),9999); socket.send(packet); } private void send() throws IOException { String message = sendText.getText(); //获取发送区域的内容 String ip =tf.getText(); //获取ip地址 ip =ip.trim().length() == 0 ? "255.255.255.255" : ip; send(message.getBytes(),ip); String time =getCurrentTime(); //获取当前时间 String str = time +"我对:"+(ip.equals("255.255.255.255")? "所有人" :ip) + "说\r\n"+message + "\r\n\r\n"; //Alt+Shift+L 抽取局部变量 viewText.append(str); //将信息添加到显示区域中 bw.write(str); //将信息写到数据库 sendText.setText(""); } private String getCurrentTime() { Date d= new Date(); //创建当前日期对象 SimpleDateFormat sdf = new SimpleDateFormat("yyyy:MM:dd HH:mm:ss"+" "); return sdf.format(d); } public void centerPanel() { Panel center =new Panel(); //创建中间的Panel viewText = new TextArea(); sendText = new TextArea(5,1); center.setLayout(new BorderLayout()); //设置为边界布局管理器 center.add(sendText, BorderLayout.SOUTH);//发送的文本区域放在南边 center.add(viewText, BorderLayout.CENTER);//显示区域放在中间 viewText.setEditable(false); //设置不可以编辑 viewText.setBackground(Color.white); sendText.setFont(new Font("xxx", Font.PLAIN, 16)); viewText.setFont(new Font("xxx", Font.PLAIN, 16)); this.add(center,BorderLayout.CENTER); } public void southPanel() { Panel south =new Panel(); //创建南边的Panel tf = new TextField(20); //双击选中 Ctrl + 1 tf.setText("127.0.0.1"); send = new Button("发送"); log = new Button("记录"); clear = new Button("清屏"); shake = new Button("震动"); south.add(tf); south.add(send); south.add(log); south.add(clear); south.add(shake); this.add(south,BorderLayout.SOUTH); //将Panel放在Frame的南边 } public void init() { this.setLocation(500,50);//位置 this.setSize(400, 600);//长宽 new Receive().start(); try { socket = new DatagramSocket(); bw =new BufferedWriter(new FileWriter("cofing.txt",true)); } catch (Exception e) { e.printStackTrace(); } this.setVisible(true);//显示 } private class Receive extends Thread{ //接受和发送需要同时执行,所以定义成多线程 public void run(){ try { DatagramSocket socket = new DatagramSocket(9999); DatagramPacket packet = new DatagramPacket(new byte[8192], 8192); while(true){ socket.receive(packet); //接受信息 byte[] arr =packet.getData(); //获取字节数据 int len =packet.getLength(); //获取有效的字节数据 if (arr[0]== -1 && len ==1) { //如果发送过来的数组第一个存储的值是-1,并且数组长度是1 shake(); //调用震动方法 continue; //终止本次循环,继续下次循环,因为震动后不需要执行下面的代码 } String message = new String(arr, 0, len); //转换成字符串 String time =getCurrentTime(); //获取当前时间 String ip =packet.getAddress().getHostAddress(); //获取ip地址 String str = time+" "+ ip +"对我说:\r\n"+ message +"\r\n\r\n"; viewText.append(str); bw.write(str); } } catch (Exception e) { e.printStackTrace(); } } } public static void main(String[] args) { new demo4_GUIChat(); } }
TCP协议
客户端
创建Socket连接服务器(指定ip 地址,端口号)通过ip地址找对应的服务器
调用Socket的getInputStream()和getOutputStream()方法获取和服务端相连的IO流
输入流可以读取服务端输出流写出的数据
输出流可以写出数据到服务端的输入流
服务端
创建SeverSocket(需要指定端口号)
调用ServerSocket的accept()方法接受一个库服端清酒,得到一个Socket
调用Socket的getInputStream()和getOutputStream()方法获取和客户端相连的IO流
输入流可以读取客户端输出流写出的数据
输出流可以写出数据到客户端的输入流