javase_21(DUp的学习-->*)
Socket网络编程
网络协议
IP地址与端口号
本地回路IP: 127.0.0.1
有效端口:0-65535(尽量使用1024个以上-->1024个以上的被占用的概率比较低)
UDP与TCP(协议)
Udp:用户数据包协议,面向无连接,不保证数据的可靠性,不安全,速度快
Tcp:传输数据协议,面向连接,提供可靠无差错的协议,安全,三次握手.
UDP传输:
DatagramSocket 和:DatagramPacket
建立发送端,接收端
建立数据包,
调用Socket的发送接收方法.
关闭Socket
发送端与接收端是两个独立运行的小程序.
发送端:
在发送端,要在数据包对象中明确的IP与端口.
1 DatagramSocket ds = 2 new DatagramSocket(); 3 Byte[] by = "hello,net".getBytes();//转换成字节 4 DatagramPacket dp = new DatagramPacket(by,0,by.length,InerAddress.getByName(127.0.0.1),10000); //数据包打包起来 5 ds.send(dp); 6 7 Ds.close();//关流
接收端:要指定监听的端口
1 datagramSocket ds = new datagramSocket(10000); 2 byte [] buf = new byte[1024]; 3 datagramPacket dp = new datagramPacket(buf,by.length); 4 ds.receive(dp);//把内容接收到dp里面去 5 String str = new String(dp,getData(),0,dp.length()); 6 System.out.println(str); 7 ds.close();
UDP聊天程序
通过键盘录入获取要发送的消息.
1 BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 2 br.readLine();
将发送和接收分别封装到两个线程中,main()线程, 和 new Thread()线程
1 发送端: 2 import java.net.DatagramSocket; 3 import java.io.IOException; 4 import java.net.DatagramPacket; 5 import java.net.InetAddress; 6 class UdpSend 7 { 8 public static void main(String[]args) 9 { 10 DatagramSocket ds = null; 11 try 12 { 13 ds = new DatagramSocket(); 14 String line = "I Come as For China"; 15 byte[]buf = line.getBytes();//转换成字节数组 16 DatagramPacket dp = 17 new DatagramPacket(buf,buf.length,InetAddress.getByName("127.0.0.1"),8888); 18 ds.send(dp); 19 } 20 catch (IOException e) 21 { 22 e.printStackTrace(); 23 }finally 24 { 25 if(ds!=null) 26 ds.close();//关闭流 27 } 28 29 } 30 } 31 32 接收端: 当开始监听端口的时候,会出现阻塞,直到监听完毕: 33 import java.net.DatagramSocket; 34 import java.io.IOException; 35 import java.net.DatagramPacket; 36 import java.net.InetAddress; 37 class UdpReceive 38 { 39 public static void main(String[] args) 40 { 41 //监听该端口 42 DatagramSocket ds = null; 43 try 44 { 45 ds = new DatagramSocket(8888); 46 DatagramPacket dp = new DatagramPacket(new byte[1024],1024); 47 //它会发生阻塞功能,首先运行这个.他会监听端口 .. 48 ds.receive(dp); 49 byte[] buf = dp.getData(); 50 String data = new String(buf,0,dp.getLength()); 51 System.out.println(data); 52 } 53 catch (IOException e) 54 { 55 e.printStackTrace(); 56 }finally 57 { 58 if(ds!=null) 59 ds.close(); 60 } 61 62 } 63 }
使用了循环的聊天方式(必须要开两个窗口)
1 发送端:() 2 import java.net.DatagramSocket; 3 import java.io.IOException; 4 import java.net.DatagramPacket; 5 import java.net.InetAddress; 6 import java.io.BufferedReader; 7 import java.io.InputStreamReader; 8 class MySend 9 { 10 public static void main(String[] args) 11 { 12 DatagramSocket ds = null; 13 BufferedReader br = null; 14 try 15 { 16 ds = new DatagramSocket(); 17 DatagramPacket dp; 18 br = new BufferedReader(new InputStreamReader(System.in)); 19 System.out.println("聊一下吧~~~"); 20 while(true) 21 { 22 String line = br.readLine(); 23 if("byte".equals(line))break;//如果return;就关闭不了流啦 24 byte[] buf = line.getBytes(); //必须要获取到正确的长度 25 dp = new DatagramPacket(buf,buf.length,InetAddress.getByName("127.0.0.1"),8888);//封装数据 26 ds.send(dp); 27 } 28 } 29 catch (IOException e) 30 { 31 e.printStackTrace(); 32 }finally 33 { 34 try 35 { 36 if(ds!=null) 37 ds.close(); 38 }finally 39 { 40 try 41 { 42 if(br!=null) 43 br.close(); 44 }catch(IOException e) 45 { 46 e.printStackTrace(); 47 } 48 } 49 } 50 51 } 52 } 53 54 接收端: 55 import java.net.DatagramSocket; 56 import java.io.IOException; 57 import java.net.DatagramPacket; 58 import java.net.InetAddress; 59 import java.io.BufferedReader; 60 import java.io.InputStreamReader; 61 class MyReceive 62 { 63 public static void main(String[] args) throws IOException 64 { 65 DatagramSocket ds = new DatagramSocket(8888);//监听端口号 66 DatagramPacket dp = new DatagramPacket(new byte[1024],1024); 67 while(true) 68 { 69 ds.receive(dp);//接收数据 70 String data = new String(dp.getData(),0,dp.getLength()); 71 if("byte".equals(data)) 72 break; 73 String ipHost = dp.getAddress().getHostName();//IP主机名字 74 String ipName = dp.getAddress().getHostAddress();//IP地址 75 int port = dp.getPort(); 76 System.out.println(ipHost+"("+ipName+")"+" "+port); 77 System.out.println(data); 78 } 79 if(ds!=null) 80 ds.close(); 81 } 82 }
-->我们需要做到的效果-->多线程实现.实现两边通信..
多线程的效果:
1 import java.net.DatagramSocket; 2 import java.io.IOException; 3 import java.net.DatagramPacket; 4 import java.net.InetAddress; 5 import java.io.BufferedReader; 6 import java.io.InputStreamReader; 7 import java.io.BufferedReader; 8 import java.io.InputStreamReader; 9 class UdpChat 10 { 11 /* 12 利用多线程来实现程序 13 Thread-0接收数据 14 Main -主线程 发送数据 15 */ 16 public static void main(String[] args) 17 { 18 new Thread(new MyChat()).start(); 19 DatagramSocket ds = null; 20 BufferedReader br = null; 21 try 22 { 23 ds = new DatagramSocket(); 24 br = new BufferedReader(new InputStreamReader(System.in)); 25 System.out.println("咱们来聊一下吧~~~"); 26 while(true) 27 { 28 String line = br.readLine(); 29 if(line.equals("byte")) 30 break; 31 byte[] buf = line.getBytes();//转换成字节数组 32 DatagramPacket dp = new DatagramPacket(buf,buf.length,InetAddress.getByName("127.0.0.1"),9089); 33 ds.send(dp); 34 } 35 } 36 catch (IOException e) 37 { 38 e.printStackTrace(); 39 } 40 } 41 } 42 43 class MyChat implements Runnable 44 { 45 public void run() 46 { 47 DatagramSocket ds = null; 48 try 49 { 50 ds = new DatagramSocket(9089); 51 DatagramPacket dp = new DatagramPacket(new byte[1024],1024); 52 while(true) 53 { 54 ds.receive(dp);//接收数据 55 byte[] buf = dp.getData(); 56 String line = new String(buf,0,dp.getLength()); 57 String ipStr = dp.getAddress().getHostAddress()+"From:"+dp.getAddress().getHostName();//主机名字 58 int port = dp.getPort(); 59 System.out.println(ipStr+port+" -- ~~"+line); 60 } 61 } 62 catch (IOException e) 63 { 64 e.printStackTrace(); 65 }finally 66 { 67 if(ds!=null) 68 ds.close(); 69 } 70 } 71 72 }
注意接收数据的时候会出现阻塞-->出现阻塞之后.您多线程怎么跑都运行不了.必须要等我发送端发送数据过去才可以.
1 获取时间: 2 String str = "本地发送于 " + DateFormat.getInstance().format(new Date()) 3 + "\r\n" + data + "\r\n";
1 聊天程序案例分析 2 一、需求 3 1.软件的界面:实现窗体Frame、显示文本TextArea或List、发送按钮Button、IP输入TextField 4 2.聊天功能:实现发送端和接收端程序(多线程) 5 3.附加功能: 保存聊天记录、关闭软件 6 7 二、实现步骤 8 1.实现软件界面的设计 9 1)创建Frame,设置大小、位置、可见 f 10 2)创建一个TextArea文本域,用于显示文字 A 11 3)创建一个TextArea文本域,用于输入文字 input 12 3)创建一个TextField单行输入框用于输入Ip,B 13 4)创建一个Button按钮,用于发送信息,C 14 2.添加事件监听 15 1)为f添加窗口监听addWindowListener(WindowAdapter),关闭窗口 16 2)为按钮C添加鼠标监听 addMouseListener(MouseAdapter),监听点击事件,发送消息,调用sendMsg 17 3)为文本域A添加键盘监听 addKeyListener(KeyAdapter) , 监听按下事件keyPressed发送消息 sendMsg 18 19 3.实现发送端 sendMsg方法 20 1)创建DatagramSocket对象,绑定闲置端口 21 2)获取input中的内容,作为message 22 3)获取B中的内容,作为Ip,这里要判断,如果没填,默认指定255.255.255.255 23 4)创建DatagramPacket对象,打包数据,统一端口7888 24 5)发送数据 ds.send(dp) 25 6)将数据和时间显示在A,append方法 26 4.实现接收端程序 27 1)软件已运行就可以收数据了,所以在构造函数中开启新线程,运行接收端 new Thread(new Runnble()).start(); 28 2)在run方法中实现接收端程序 29 3)创建DatagramSocket对象,监听7888端口 30 4)准备数据包 31 5)接受数据,阻塞,这个要做在循环里面 ds.receive(dp) 32 6)获得数据和对方的Ip , new String(dp.getData(), 0, dp.getLength())\dp.getInetAddress().getHostAddress\(dp.getPort) 33 7)获得当前时间, DateFormat.getInstance().format(new Date()); 34 8)将数据显示在A,append方法 35 36 37 38 import java.awt.BorderLayout; 39 import java.awt.Button; 40 import java.awt.Frame; 41 import java.awt.Panel; 42 import java.awt.TextArea; 43 import java.awt.TextField; 44 import java.awt.event.KeyAdapter; 45 import java.awt.event.KeyEvent; 46 import java.awt.event.MouseAdapter; 47 import java.awt.event.MouseEvent; 48 import java.awt.event.WindowAdapter; 49 import java.awt.event.WindowEvent; 50 import java.io.FileWriter; 51 import java.io.IOException; 52 import java.net.DatagramPacket; 53 import java.net.DatagramSocket; 54 import java.net.InetAddress; 55 import java.net.SocketException; 56 import java.text.DateFormat; 57 import java.util.Date; 58 59 class MyChatTest 60 { 61 public static void main(String[] args) 62 { 63 MyChatOne mc = new MyChatOne(); 64 } 65 } 66 67 class MyChatOne 68 { 69 private Frame f; 70 private TextArea disPlay,dataInput; 71 private TextField ipInput;//IP地址的读取(单行文本可编程的组件) 72 private Button senBtn; 73 private boolean close = false; 74 public MyChatOne() 75 { 76 f = new Frame(); 77 f.setSize(370,500); 78 f.setLocation(100,150); 79 f.setResizable(false);//不可移动 80 disPlay = new TextArea(23,30); 81 disPlay.setEditable(false);//不可编辑 82 dataInput = new TextArea(10,30); 83 ipInput = new TextField(20); 84 senBtn = new Button("发送(Ctrl+Enter)"); 85 86 f.add(disPlay,"North"); 87 f.add(dataInput,"Center"); 88 Panel p = new Panel(new BorderLayout()); 89 p.add(ipInput,"West");//西边 90 p.add(senBtn,"East");//北' 91 f.add(p,"South");//南 92 f.setVisible(true); 93 handEvent(); 94 new Thread(new ReceiveInMyChat()).start(); 95 } 96 97 //监听 98 private void handEvent() 99 { 100 f.addWindowListener(new WindowAdapter(){ 101 public void windowClosing(WindowEvent e) 102 { 103 e.getWindow().dispose(); 104 close = true; 105 ipInput.setText("127.0.0.1");//阻塞,随便运行一下发送端就可以. 106 } 107 }); 108 senBtn.addMouseListener(new MouseAdapter(){ 109 public void mouseClicked(MouseEvent e) 110 { 111 sendMsg();//当您触发我的确定按钮.我需要做的事情.. 112 } 113 }); 114 dataInput.addKeyListener(new KeyAdapter(){ 115 //监听编辑器.当按下键盘并且+回车..你懂的.. 116 public void keyPressed(KeyEvent e) 117 { 118 if(e.isControlDown()&&e.getKeyChar()=='\n') 119 sendMsg(); 120 } 121 }); 122 123 124 } 125 126 private void sendMsg() 127 { 128 //实现发送端的程序 129 DatagramSocket ds = null; 130 try 131 { 132 ds = new DatagramSocket(); 133 String data = dataInput.getText();//获取里面的数据 134 String ip = ipInput.getText();//获取单行编辑条的内容 135 if(ip.length()==0) 136 { 137 ip = "127.0.0.1"; 138 ipInput.setText(ip);//如果没有.我也必须往里面写入数据 139 } 140 byte[] buf = data.getBytes();//获取字节数组 141 142 //封包 143 DatagramPacket dp = 144 new DatagramPacket(buf,buf.length,InetAddress.getByName(ip),8888);//封装数据 145 //发包 146 ds.send(dp); 147 //将信息显示在display()这边 148 String str = "本地发送于 " + DateFormat.getInstance().format(new Date()) 149 + "\r\n" + data + "\r\n"; 150 disPlay.append(str);//追加内容到这边来 151 dataInput.setText("");//表示清空内容~ 152 saveMessage(str); 153 //等一下我们可以做一下聊天记录 154 } 155 catch (IOException e) 156 { 157 e.printStackTrace(); 158 }finally 159 { 160 if(ds!=null) 161 ds.close(); 162 } 163 } 164 165 //接收端咱们用多线程实现 166 class ReceiveInMyChat implements Runnable 167 { 168 @Override 169 public void run() 170 { 171 DatagramSocket ds = null; 172 try 173 { 174 ds = new DatagramSocket(8888);//指定需要监听的端口号 175 DatagramPacket dp = new DatagramPacket(new byte[1024],1024); 176 while(true) 177 { 178 //阻塞-->必须要执行内容才可以到这一步.但我们到这一步.可以把多线程退出. 179 ds.receive(dp); 180 if(close) 181 break;//跳出循环.多线程就会关闭 182 String data = new String(dp.getData(),0,dp.getLength()); 183 String ip = dp.getAddress().getHostAddress()+"("+dp.getAddress().getHostName()+")"; 184 String str = ip + " 发送于 " + DateFormat.getInstance().format(new Date()) 185 + "\r\n" + data + "\r\n"; 186 disPlay.append(str); 187 saveMessage(str); 188 } 189 } 190 catch (IOException e) 191 { 192 e.printStackTrace(); 193 }finally 194 { 195 if(ds!=null) 196 ds.close(); 197 } 198 } 199 } 200 201 202 /* 203 聊天记录的保存: 204 */ 205 private void saveMessage(String str) 206 { 207 FileWriter fw = null; 208 try 209 { 210 fw = new FileWriter("d:/聊天记录.txt",true);//表示从后面追加 211 fw.write(str); 212 } 213 catch (IOException e) 214 { 215 e.printStackTrace(); 216 } 217 finally 218 { 219 try 220 { 221 if(fw!=null) 222 fw.close();//关流. 223 } 224 catch (IOException e) 225 { 226 e.printStackTrace(); 227 } 228 } 229 } 230 } 231 232 233 多线程的回顾: 234 package com.javami.kudyDemo.udpStudy; 235 236 public class ThreadDemo { 237 238 /** 239 * 主要内容复习下多线程的回归,..主线程必须执行先~~ 240 */ 241 public static void main(String[] args) { 242 new Thread(new MyThread()).start(); 243 for(int i=0; i<10; i++) 244 { 245 System.out.println("主线程!!!"); 246 } 247 } 248 249 } 250 251 class MyThread implements Runnable 252 { 253 public void run() 254 { 255 int num = 0; 256 while(true) 257 { 258 System.out.println("To Learn How"); 259 num ++; 260 if(num>10) 261 break; 262 } 263 } 264 }
心得与总结:
多线程需要复习-->
首先在接收数据的时候.会遇到阻塞-->必须要运行一下发送端程序..
时间这个类也得复习..
明天早上起来的任务-->必须要回顾知识..和敲写多一次这个程序.
今天的时间掌握得还是比较不好的~~希望下次好好努力改正..需要认真去对待每一件事..
多背下单词.