网络编程三要素: A:IP地址 B:端口 C:协议 举例: 我想要和林青霞说话了。肿么办? A:我要找到林青霞。 B:对她说话,要对耳朵说 C:我说什么呢?"I Love You" 但是,她没学过英语,听不懂 我没必要说英语,说汉语就可以了:我爱你 IP地址: 网络中计算机的唯一标识 计算机只能识别二进制的数据,所以我们的IP地址应该是一个二进制的数据。 但是我们配置的IP地址不是二进制的,为什么呢? IP:192.168.1.100 换算:11000000 10101000 00000001 01100100 假如真是:11000000 10101000 00000001 01100100 我们如果每次使用网络就这样配置IP地址,记忆起来很麻烦 所以为了方便表示IP地址,我们就把IP地址每一个字节上的数据换算成为十进制,然后用.隔开来表示: “点分十进制” IP地址的组成:网络号段+主机号段 A类:一个号段为网络号段+后三段的主机号段 一个网络号:256*256*256=16777216 B类:前二号段为网络号段+后两段的主机号 一个网络号:256*256=65536 C类:前3号段为网络号段+后一段的主机号段 一个网络号:256 两个DOS命令: ipconfig:查看本机地址 ping 后面跟ip地址:测试本机与指定的IP地址间的通信是否有问题 特殊的ip地址 127.0.0.1 回环地址(表示本机) x.x.x.255广播地址 x.x.x.0网络地址 为了方便使用IP,java提供InetAccess 端口: 正在运行的程序的标识 有效端口:0~65535,其中0~1024系统使用或者保留。可以使用360查看各个程序的端口 协议: 通信的规则 UDP: 把数据打包 数据有限制64k 不建立连接 速度快 不可靠 TCP: 建立连接通道 数据无限制 速度慢 可靠 举例: UDP:发短信 TCP:打电话
InetAccess:
package com.gz_02; import java.net.InetAddress; import java.net.UnknownHostException; /* * 如果一个类没有构造方法: * A:成员方法全部是静态的 * B:单例模式 * C:类中有静态方法返回该类的对象 * * * 看InetAddress的成员方法: * public static InetAddress getByName(String host) 根据主机名或者IP地址的字符串表示得到I[地址对象 */ public class InetAddressDemo { public static void main(String[] args) throws UnknownHostException { InetAddress address=InetAddress.getByName("192.168.1.100"); //publicStringgetHostName() String name=address.getHostName(); //public String getHostAddress() String ip=address.getHostAddress(); System.out.println(name+"---"+ip); } }
UDP:
package com.gz_03; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; /* * UDP协议接受数据: * A:创建发送端Socket对象 * B:创建一个数据包(接受容器) * C:调用Socket对象的接受方法接受方法 * D:解析数据包并显示在数据台 * D:释放资源 * */ public class ReceiveDemo { public static void main(String[] args) throws IOException { //创建Socket对象 //DatagramSocket(int port) DatagramSocket ds=new DatagramSocket(10670); //创建一个数据包(接受容器) //DatagramPacket(byte[] buf,int length) byte[] bys=new byte[1024]; int length=bys.length; DatagramPacket dp=new DatagramPacket(bys, length); //调用Socket对象的接受方法接受数据,在接受到数据前一直被阻塞 //public void receive(DatagramPacket p) ds.receive(dp); //接受到了数据要显示下 //解析数据包,并显示在数据台 //byte[] getData() //int getLength()获取数据长度 byte[] bys2=dp.getData(); int len=dp.getLength(); String s=new String(bys2,0,len); //获取对方ip //public InetAddress getAddress() InetAddress address=dp.getAddress(); String ip=address.getHostAddress(); System.out.println(ip+":"+s); //释放资源 ds.close(); } } package com.gz_03; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.SocketException; import java.net.UnknownHostException; /* * UDP协议发送数据: * A:创建发送端Socket对象 * B:创建数据,并把数据打包 * C:调用Socket对象的发送方法发送数据包 * D:释放资源 */ public class SendDemo { public static void main(String[] args) throws IOException { //创建发送端Socket对象 //DatagrameSocket() DatagramSocket ds=new DatagramSocket(); //创建数据,并把数据打包 //DatagramPacket(byte[] buf,int length,InetAddress address,int port) //创建数据 byte[] bys="我是郭祯".getBytes(); //长度 int length=bys.length; //IP地址对象 // InetAddress address=InetAddress.getByName("192.168.1.129"); InetAddress address=InetAddress.getByName("192.168.1.129"); //端口 // int port=6000; int port=10670; DatagramPacket dp=new DatagramPacket(bys, length, address, port); //调用Socket对象的发送方法发送数据包 //public void send(DatagreamPacket p) ds.send(dp); //释放资源 ds.close(); } }
UDP简单聊天:
package com.gz_06; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.Scanner; /* * UDP协议发送数据: * A:创建发送端Socket对象 * B:创建数据,并把数据打包 * C:调用Socket对象的发送方法发送数据包 * D:释放资源 */ public class SendThread implements Runnable { private DatagramSocket ds; public SendThread(DatagramSocket ds){ this.ds=ds; } @Override public void run() { try{ while(true){ Scanner input=new Scanner(System.in); String str=input.nextLine(); DatagramPacket dp=null; try { dp=new DatagramPacket(str.getBytes(), str.getBytes().length, InetAddress.getByName("192.168.1.100"), 12306); } catch (UnknownHostException e) { e.printStackTrace(); } ds.send(dp); } }catch(IOException e){ e.printStackTrace(); }finally{ ds.close(); } } } package com.gz_06; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; /* * UDP协议接受数据: * A:创建发送端Socket对象 * B:创建一个数据包(接受容器) * C:调用Socket对象的接受方法接受方法 * D:解析数据包并显示在数据台 * D:释放资源 * */ public class ReceieveThread implements Runnable { private DatagramSocket ds; public ReceieveThread(DatagramSocket ds){ this.ds=ds; } @Override public void run() { try{ while(true){ byte[] buff=new byte[1024]; DatagramPacket dp=new DatagramPacket(buff, buff.length); ds.receive(dp); byte[] b=dp.getData(); InetAddress ia=dp.getAddress(); String ip=ia.getHostAddress(); System.out.println(ip+":"+new String(b,0,dp.getLength())); } }catch(IOException e){ e.printStackTrace(); }finally{ ds.close(); } } } package com.gz_06; import java.io.IOException; import java.net.DatagramSocket; public class CharRoom { public static void main(String[] args) throws IOException{ DatagramSocket st=new DatagramSocket(); DatagramSocket ds=new DatagramSocket(12306); SendThread sd=new SendThread(st); ReceieveThread re=new ReceieveThread(ds); new Thread(sd).start(); new Thread(re).start(); } }
TCP:
package com.gz_07; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; /* * A:创建发送端的Socket对象 * 这一步如果成功,就说明连接已经成功了 * B:获取输出流,写数据 * C:释放资源 * *Connection refused *连接被拒绝。tcp一定要服务器被开启,因为tcp要建立连接 *而ucp不需要,ucp不保证数据一定过去对面接收到 */ public class ClientDemo { public static void main(String[] args) throws IOException { //创建发送端的Socket对象 //Socket(InetAdderss address,int port) //Socket(String host,int port) Socket s=new Socket("192.168.1.100",8888); //获取输出流,写数据 OutputStream os=s.getOutputStream(); os.write(("hello,tcp,我来了").getBytes()); InputStream in=s.getInputStream(); byte[] b=new byte[1024]; int t=in.read(b);//阻塞式 String str=new String(b,0,t); System.out.println(str); s.close(); } } package com.gz_07; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; /* * TCP协议接受数据 * A:创建接收端的Socket对象 * B:监听客户端连接返回一个对应的Socket对象 * C:获取输入流读取数据,显示在控制台 * D:释放资源 */ public class ServerDemo { public static void main(String[] args) throws IOException { //ServerSocket(port) ServerSocket s=new ServerSocket(8888); Socket ss=s.accept();//阻塞式方法,侦听并接受到此套间的连接,返回对应的Socket对象 InputStream is=ss.getInputStream(); byte[] bys=new byte[1024]; int len=is.read(bys); String str=new String(bys,0,len); String str1=ss.getInetAddress().getHostAddress(); System.out.println(str1+":"+str); OutputStream os=ss.getOutputStream(); os.write("收到了".getBytes()); ss.close(); //s.close();服务器不应该关闭 } }
关于反馈:
package com.gz_08; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; public class ServerDemo02 { public static void main(String[] args) throws IOException { ServerSocket ss=new ServerSocket(8888); Socket s=ss.accept();//阻塞式 排除 System.out.println(s.getInetAddress().getHostAddress()); BufferedReader br=new BufferedReader(new InputStreamReader(s.getInputStream())); BufferedWriter bw=new BufferedWriter(new FileWriter("copy.txt")); String line=null; while((line=br.readLine())!=null){ //阻塞式 阻塞了 无法判断得到的输入流是否是结束的,所以一直在等待,怎么办呢? //方式一:自定义一个结束标记,这里收到结束标记就不等待了。自定义结束标记如果文件中存在自定义结束标记就会出问题。其他还好 //方式二:java api提供了一个方法s.shutdownOutput(); 写入关闭,也就是完成 // if("over".equals(line)){ // break; // } bw.write(line); bw.newLine(); bw.flush(); } //接受到了数据,我希望给出一个反馈 OutputStream os=s.getOutputStream(); os.write("完成上传!".getBytes()); //经过测试,我们发现:程序不是按照我们想要的流程走。它迟迟不给出反馈。这是为什么呢?我们有几个阻塞式方法,问题肯定是出现在那里的 //判断是在这里的while循环的read方法处阻塞了 s.close(); } } package com.gz_08; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.net.Socket; import java.net.UnknownHostException; public class ClientDemo02 { public static void main(String[] args) throws UnknownHostException, IOException { Socket s=new Socket("192.168.1.100",8888); BufferedReader br=new BufferedReader(new FileReader("src/网络编程三要素")); BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(s.getOutputStream())); String line=null; while((line=br.readLine())!=null){ bw.write(line); bw.newLine(); bw.flush(); } // bw.write("over"); // bw.newLine(); // bw.flush(); s.shutdownOutput();//写入完成 BufferedReader fr=new BufferedReader(new InputStreamReader(s.getInputStream())); byte[] b=new byte[1024]; String str=fr.readLine(); System.out.println(str); br.close(); bw.close(); } }
多线程模拟:
package com.gz_09; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.net.Socket; public class UploadClient { public static void main(String[] args) throws IOException { // 创建客户端Socket对象 Socket s = new Socket("192.168.1.100", 11101); // 封装文本文件 // BufferedReader br = new BufferedReader(new FileReader( // "InetAddressDemo.java")); BufferedReader br = new BufferedReader(new FileReader( "TCP编程")); // 封装通道内流 BufferedWriter bw = new BufferedWriter(new OutputStreamWriter( s.getOutputStream())); String line = null; while ((line = br.readLine()) != null) { // 阻塞 bw.write(line); bw.newLine(); bw.flush(); } // Socket提供了一个终止,它会通知服务器你别等了,我没有数据过来了 s.shutdownOutput(); // 接收反馈 BufferedReader brClient = new BufferedReader(new InputStreamReader( s.getInputStream())); String client = brClient.readLine(); // 阻塞 System.out.println(client); // 释放资源 br.close(); s.close(); } } package com.gz_09; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; public class UploadServer { public static void main(String[] args) throws IOException { // 创建服务器Socket对象 ServerSocket ss = new ServerSocket(11101); while (true) { Socket s = ss.accept(); new Thread(new UserThread(s)).start(); } } } package com.gz_09; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.net.Socket; public class UserThread implements Runnable { private Socket s; public UserThread(Socket s) { this.s = s; } @Override public void run() { try { // 封装通道内的流 BufferedReader br = new BufferedReader(new InputStreamReader( s.getInputStream())); // 封装文本文件 // BufferedWriter bw = new BufferedWriter(new // FileWriter("Copy.java")); // 为了防止名称冲突 String newName = System.currentTimeMillis() + ".java"; BufferedWriter bw = new BufferedWriter(new FileWriter(newName)); String line = null; while ((line = br.readLine()) != null) { // 阻塞 bw.write(line); bw.newLine(); bw.flush(); } // 给出反馈 BufferedWriter bwServer = new BufferedWriter( new OutputStreamWriter(s.getOutputStream())); bwServer.write("文件上传成功"); bwServer.newLine(); bwServer.flush(); // 释放资源 bw.close(); s.close(); } catch (IOException e) { e.printStackTrace(); } } }
前面一直以为使用TCP同一个Socket不可以多次通信。现在发现单纯使用flush方法不使用shutdownInput或者shutdownOutput也可以在服务器读取多次并回复多次。
代码:
package com.client; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.Socket; import java.net.UnknownHostException; import com.hh.ReadDemo; import com.hh.WriterDemo; public class ClientDemo { /** * 项目需求分析: * 客户端发送数据支持对线程,所以服务器接收数据也应该是多线程 * 现在主要是想测试一下直接使用一个Tcp进行聊天并且多条语句 */ private Socket s=null; DataInputStream dis=null; DataOutputStream dos=null; public static void main(String[] args) { ClientDemo cd=new ClientDemo(); cd.init(); System.out.println("可以和服务器进行交流了"); //while(true){ 不能新建太多线程,所以我尝试将while循环卸载线程的run方法 new Thread(new ReadDemo(cd.s)).start(); new Thread(new WriterDemo(cd.s)).start(); //} } public void init(){ try { s=new Socket("127.0.0.1",8888); dis=new DataInputStream(s.getInputStream()); dos=new DataOutputStream(s.getOutputStream()); } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } // public void write(){ // Scanner sc=new Scanner(System.in); // String s=sc.next(); // try { // dos.writeUTF(s); // dos.flush(); // } catch (IOException e) { // e.printStackTrace(); // } // } // public void read(){ // try { // String s=dis.readUTF(); // System.out.println(s); // } catch (IOException e) { // e.printStackTrace(); // } // } } package com.server; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import com.hh.ReadDemo; import com.hh.WriterDemo; public class ServerDemo { public static void main(String[] args) { try { ServerSocket server=new ServerSocket(8888); Socket s=server.accept(); //while(true){ new Thread(new ReadDemo(s)).start(); new Thread(new WriterDemo(s)).start(); //} } catch (IOException e) { e.printStackTrace(); } } } package com.hh; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.Socket; public class ReadDemo implements Runnable{ private Socket s; private DataInputStream dis=null; private DataOutputStream dos=null; public ReadDemo(Socket s){ this.s=s; try { dis=new DataInputStream(s.getInputStream()); dos=new DataOutputStream(s.getOutputStream()); } catch (IOException e) { e.printStackTrace(); } } @Override public void run() { try { while(true){ String str=dis.readUTF(); System.out.println(str); } } catch (IOException e) { e.printStackTrace(); } } } package com.hh; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.Socket; import java.util.Scanner; public class WriterDemo implements Runnable{ private Socket s; private DataInputStream dis=null; private DataOutputStream dos=null; public WriterDemo(Socket s){ this.s=s; try { dis=new DataInputStream(s.getInputStream()); dos=new DataOutputStream(s.getOutputStream()); } catch (IOException e) { e.printStackTrace(); } } @Override public void run() { while(true){ Scanner sc=new Scanner(System.in); try { String str=sc.next(); dos.writeUTF(str); dos.flush(); } catch (IOException e) { e.printStackTrace(); } } } }