1,IP地址和InetAddress
IP地址是互联网上每台计算机都有的自己的标记,IP地址分为5类,A类保留给*,B类给中等规模的公司,C类给任何需要的人,D类用于组播,E类用于实验.
A类 1.0.0.1-126.255.255.254 B类 128.0.0.1-191.255.255.254 C类 192.0.0.1-223.255.255.254 D类 244.0.0.1-239.255.255.254
E类 240.0.0.1-255.255.255.254
在以后开发的时候,经常使用的127.0.0.1表示的是本机的IP地址
InetAddress
该类主要表示的是IP地址,有两个子类,Inet4Address和Inet6Address
该类没有构造函数,但是有提供了静态的方法去获得该类的对象
我们去获取本家的IP地址等一些信息的时候,先通过该类的静态方法去得到一个InetAddress的对象,有了对象后,通过该类中的各种方法,去获取相信的信息,比如需要打印出IP地址的话,使用的肯定是返回值为String的方法.
package cn.wjd.ip; import java.net.InetAddress; public class IPDemo { public static void main(String[] args) throws Exception { //获取本地地址IP对象 InetAddress ip = InetAddress.getLocalHost(); ip = InetAddress.getByName("www.baidu.com");//本地DNS hosts System.out.println(ip.getHostAddress()); System.out.println(ip.getHostName()); } }
2,UDP程序设计
UDP是不可靠的连接协议,这种协议在各种聊天工具中被广泛的使用,在java中使用DatagramSocket来完成对信息的发送,使用DatagramPacket来包装一条需要发送的信息
package cn.net; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.LineNumberReader; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.UnknownHostException; public class Send implements Runnable { // 创建UDP的Socket流对象 private DatagramSocket ds = null; public Send(DatagramSocket ds) { super(); this.ds = ds; } public void run() { try { BufferedReader bufr = new BufferedReader(new InputStreamReader( System.in)); String line = null; while ((line = bufr.readLine()) != null) { byte[] buf = line.getBytes(); DatagramPacket dp = new DatagramPacket(buf, buf.length, InetAddress.getByName("wjd"), 9999); ds.send(dp); if("88".equals(line)) break; } ds.close(); } catch (Exception e) { e.printStackTrace(); } } } package cn.net; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; public class Rece implements Runnable{ private DatagramSocket ds = null; public Rece(DatagramSocket ds) { super(); this.ds = ds; } public void run(){ try { while(true){ byte[] buf = new byte[1024]; DatagramPacket dp = new DatagramPacket(buf,buf.length); ds.receive(dp); int port = dp.getPort(); String ip = dp.getAddress().getHostName(); String text = new String(dp.getData(),0,dp.getLength()); System.out.println("ip:"+ip+" port:"+port+" text:"+text); if("88".equals(text)){ System.out.println("退出聊天!!"); } //ds.close(); } }catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } package cn.net; import java.net.DatagramSocket; import java.net.SocketException; public class Chat { public static void main(String[] args) throws SocketException { DatagramSocket rece = new DatagramSocket(9999); DatagramSocket send = new DatagramSocket(); Send s = new Send(send); Rece r = new Rece(rece); Thread t1 = new Thread(s); Thread t2 = new Thread(r); t1.start(); t2.start(); } }
创建一个UDP的客户端,用来接受数据
发送端: 1,创建UDP的socket流,datagramsocket
2,创建键盘输入流,system.in
3,将需要的信息通过datagrampacket进行封装,封装的内容包括数据包的大小byte数组,长度,IP地址,发送信息的时候,必须要明确端口号
4,通过UDP的socket流来发送数据包
5,关闭UDP的socket流
接收端:1,创建UDP的socket流,datagramsocket
2,创建一个byte数组,用UDP的socket流来接受数据包
3,通过接受到的数据包,获取数据包的中内容,包括里面的内容,IP地址,端口号等
注意点:在发送端方面,对数据包进行实例化的时候,需要在其构造方法中明确,数据的内容(byte数组),数据的长度,要发送的目标地址,发送的端口,这个端口号是在datagrampacket,封装数据包的构造函数的时候明确的.
在接收端方面,创建数据包的接受对象,和UDP的socket流对象(在这个流对象中要明确我们在发送信息的时候,需要在哪个端口监听,与发送端的端口号要一致)
3,URL和URLConnection
URL是统一资源定位符,可以使用此类找到互联网上的资源(比如一个简单的网页)
URLConnection是封装访问远程网络资源一般方法的类,通过它可以建立与远程服务器的连接,检查远程资源的一些属性
package cn.wjd.ie_server; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; public class URLDemo { public static void main(String[] args) throws IOException { String url_str = "http://127.0.0.1:8080/myweb/reg.html"; URL url = new URL(url_str); //InputStream in = url.openStream(); //获取URL对象的url连接器对象,将连接封装成对象:java中内置可以解析具体协议的的对象+socket URLConnection conn = url.openConnection(); System.out.println(conn.toString()); //sun.net.www.protocol.http.HttpURLConnection:http://127.0.0.1:8080/myweb/reg.html byte[] buf = new byte[2588]; // int len = in.read(buf); // String test = new String(buf,0,len); // System.out.println(test); } }
4,TCP程序设计
在Java中,使用Socket来完成TCP程序的开发,使用此类可以方便的建立可靠的,双向的,持续的,点对点的通信连接.
在客户端当面,我们可以直接创建Socket对象,在服务端,先创建ServerSocket对象,通过该对象的accept方法,来获取到Socket,也就是说在整个TCP的信息的流通中,都是通过这个socket流来完成的.
ServerSocket类与Socket类
ServerSocket类是主要用于服务端程序的开发,用于接受客户端的连接请求,在服务器端每次运行时都是使用accept()方法等待客户端连接,此方法执行后,服务器端将进入阻塞状态,直到客户端连接之后程序才可以向下执行,此方法的返回值是Socket,每一个Socket都便是一个客户端对象.
大白话理解的话,在TCP客户端和服务端进行数据通讯的时候,存在的是一个Socket流,这个流首先是由客户端通过outputstream的形式发出的流通的管道中,然后到了服务端这边,我们得先ServerSocket对象,然后通过该实例化对象,来拿到管道中的Socket流,然后在通过inputstream来获取到这个管道中的信息.
但是在最后运行的时候,由于accept这个方法是阻塞的,我们得先运行服务端,再运行客户端这样才能顺利的进行通讯.
编写TCP客户端的步骤
1,创建Socket对象,同时指定要连接服务器的主机名称和连接端口号
2,创建Socket输出流,将需要发送的数据变成字节的形式(在Socket流中走的数据都是以字节的形式存在的),放在socket流中,在客户端中,发送信息,客户端->服务器端(out) 在服务器端反馈信息 服务器端->客户端(in)
3,关闭socket流
package cn.tcp; import java.io.IOException; import java.io.OutputStream; import java.net.InetAddress; import java.net.Socket; import java.net.UnknownHostException; public class Client { public static void main(String[] args) throws UnknownHostException, IOException { Socket s = new Socket(InetAddress.getByName("wjd"),8767); OutputStream out = s.getOutputStream(); out.write("我是来发送数据的!!".getBytes()); s.close(); } }
编写TCP服务端的步骤
1,创建ServerSocket对象,在该对象的构造方法中,必须要明确客户端那边的端口号
2,使用accept()方法,来获取Socket流.
3,由于客户端那边已经out信息给服务端了,那么我们在服务端就要in信息出来, 搞了inoutstream对象,这样在TCP通信中就形成了一个完整的Socket流,有输出有输入
4,对in进行读取操作,读出客户端发给服务端的信息,然后将字节变成String,进行输出
5,关闭s流和ss流
package cn.tcp; import java.io.IOException; import java.io.InputStream; import java.net.ServerSocket; import java.net.Socket; public class Server { public static void main(String[] args) throws IOException { ServerSocket ss = new ServerSocket(8767); Socket s = ss.accept(); InputStream in = s.getInputStream(); String ip = s.getInetAddress().getHostAddress(); int len = 0; byte[] buf = new byte[1024]; len = in.read(buf); String str = new String(buf,0,len); System.out.println("接受客户端的内容:"+str+" ip:"+ip); ss.close(); s.close(); } }
客户端和服务端进行数据交互,当在客户端输入小写字母的时候,在服务端进行处理,变成大写字母,反馈给客户端进行输出
客户端: 客户端->服务端发送信息 源键盘 目的socket的输出流(使用printWriter)
服务端->客户端反馈信息 socket输入流,来接受服务端处理好的信息,并将处理好的信息打印到控制台上去
服务端: 接受客户端的信息 socket输入流, 服务端->客户端返回处理好的信息 printWriter流
readLine()是根据判断是否有换行来结束,所以在printwriter进行输出的时候,一定是println,这样才会有换行的标记
printwriter进行输出的时候,一定要进行刷新的动作,如果不刷新的话,数据只会进入printwriter流中,而不会进入socket流
package cn.tcp; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; public class TransServer { public static void main(String[] args) throws IOException { //获取socket流 ServerSocket ss = new ServerSocket(10000); Socket s = ss.accept(); System.out.println(s.getInetAddress().getHostAddress()); //获取socket输出流 客户端->服务端的信息 BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream())); //获取socket输出流 服务端->客户端 信息的反馈 PrintWriter out = new PrintWriter(s.getOutputStream(),true); //进行读写操作 String line; while((line=bufIn.readLine())!=null){ System.out.println(line); //将字母小写变成大写 String strUpper = line.toUpperCase(); //通过Socket流,服务端->客户端信息的反馈,将大写字母给到客户端去显示 out.println(strUpper); } } }
package cn.tcp; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.InetAddress; import java.net.Socket; import java.net.UnknownHostException; public class TransClient { public static void main(String[] args) throws UnknownHostException, IOException { //创建Socket流 Socket s = new Socket(InetAddress.getByName("wjd"),10000); //创建源 键盘输入 BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in)); //创建socket输出流 客户端->服务端 PrintWriter out = new PrintWriter(s.getOutputStream(),true); //创建socket流,用来接受服务端的反馈信息 BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream())); //进行键盘读写操作 String line; while((line=bufr.readLine())!=null){ if("over".equals(line)) break; out.println(line); //读取服务端返回的信息,该信息已经在服务端,把小写字母变成大写字母了. String strUpper = bufIn.readLine(); System.out.println(strUpper); } s.close();//在socket流中植入了结束的标记 } }
TCP从客户端上上传图片或者文本文件到服务器
在Java IO中,到需要操作到文本文件的时候,源和目的的明确,使用到的是fileinputstream和fileoutputstream
操作图片.歌曲这些字节的时候,源和目的的明确,使用到的是filewriter和filereader
由于客户端和服务端之间有数据的交互,所以以后碰到该类问题的时候,我们在服务端完成数据传输动作的时候,必须要告诉服务端,这个时候客户端已经把事情办完了,不告诉服务端的话,服务端会一直处于等待状态,服务端的程序就不会结束,这个时候就得用到socket流中的一个方法
服务器在操作文本数据,写入数据的时候,由于这边使用到了缓冲区,那么在写完数据的时候,必须要做一次刷新缓冲区的这个动作.
以后操作文本文件,这类的字符文件的时候,需要输出的话,可以优先考虑到IO中的打印流,打印流是输出信息最方便的类.
package cn.tcp; import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.InetAddress; import java.net.Socket; import java.net.UnknownHostException; public class UploadTXTClient { public static void main(String[] args) throws UnknownHostException, IOException { //创建socket流,明确地址和端口号 Socket s = new Socket(InetAddress.getByName("wjd"),10002); //明确上传文件的源文件的地址 BufferedReader bufr = new BufferedReader(new FileReader("各种需求.txt")); //创建socket输出流 客户端->服务端 PrintWriter out = new PrintWriter(s.getOutputStream(),true); String lin = null; //读取上传文件的(源文件)的信息,然后再通过打印流,就数据进入到socket流中去 while((lin=bufr.readLine())!=null){ out.println(lin); } //告诉服务器端,客户端这边的TXT文件的数据已经读完了 s.shutdownOutput(); //拿到服务端到客户端反馈的信息 BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream())); String str = bufIn.readLine(); System.out.println(str); bufr.close(); s.close(); } }
package cn.tcp; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; public class UploadTXTServer { public static void main(String[] args) throws IOException { //得到socket流 ServerSocket ss = new ServerSocket(10002); Socket s = ss.accept(); System.out.println(s.getLocalAddress().getHostAddress()+"connection..."); //确定需要上传后的文件的名称和目的 BufferedWriter bufw = new BufferedWriter(new FileWriter("load.txt")); //得到socket中的输入流 BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream())); String lin = null; //拿到socket流中的数据,进行读取,并写入指定的文件 while((lin=bufIn.readLine())!=null){ bufw.write(lin); bufw.newLine(); //由于使用了缓冲区,这边必要要刷新,才能将数据写入到目的文件中去 bufw.flush(); } PrintWriter out = new PrintWriter(s.getOutputStream(),true); out.println("OK!!"); ss.close(); s.close(); } }
package cn.tcp; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.InetAddress; import java.net.Socket; import java.net.UnknownHostException; public class LoadMP3Clinet { public static void main(String[] args) throws UnknownHostException, IOException { Socket s = new Socket(InetAddress.getByName("wjd"),10003); FileInputStream fis = new FileInputStream("1.mp3"); OutputStream out = s.getOutputStream(); byte[] buf = new byte[1024]; int len = 0; while((len=fis.read(buf))!=-1){ out.write(buf, 0, len); } s.shutdownOutput(); InputStream in = s.getInputStream(); byte[] serverBuf = new byte[1024]; int serverLen = 0; while((serverLen=in.read(serverBuf))!=-1){ String str = new String(serverBuf,0,serverLen); System.out.println(str); } } }
package cn.tcp; import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; public class LoadMP3Server { public static void main(String[] args) throws IOException { ServerSocket ss = new ServerSocket(10003); Socket s = ss.accept(); System.out.println(s.getInetAddress().getHostName()+"以连接上...."); FileOutputStream fos = new FileOutputStream("server.mp3"); InputStream in = s.getInputStream(); byte[] buf = new byte[1024]; int len = 0; while((len=in.read(buf))!=-1){ fos.write(buf, 0, len); } OutputStream out = s.getOutputStream(); out.write("上传成功...".getBytes()); ss.close(); s.close(); } }