java网络编程

来源:互联网 发布:富春山居图有多烂 知乎 编辑:程序博客网 时间:2024/06/05 14:46

一.网络基础知识

1.OSI(Open System Interconnection)七层模型和TCP/IP协议


2.七层模型与协议之间的对应关系



3.网络编程三要素:

1)IP地址:每台电脑都有唯一的标识:ip

常用的IP  A类:1网络+3主机  可连接主机个数 2563  通常大学里面或一些政府部门(1-127)

B类:2网络+2主机  可连接主机个数 256(128-191)

C类:3网络+1主机 可连接主机个数 256(192-223)

127.0.0.1:回环地址(也可以表示本机地址)

xxx.xxx.xxx.255广播地址

ping ip地址:查看当前本机与这台PC机器的网络通信

2)端口:两台PC通信,除了知道IP地址,还要知道端口号

有效端口号:0-65535

保留端口好:0-1024

3)协议:TCP协议和UDP协议区别:

TCP(传输控制协议):

建立连接通道(通道内的流使用的是最基本的字节流)

可靠协议

服务器要等待客户端连接,执行效率低

使用TCP协议可以发送大量的数据,文件大小无限制

UDP(用户数据报协议):

无需建立连接通道(数据包的形式)

不可靠协议

执行效率高

UDP发送数据有限制

4.如果一个类没有构造方法(三种情况)

1)这个类里面的成员方法都是静态(Math、Arrays、Collections)

2)单例模式:在内存始终只有一个对象,将构造方法私有化,在成员变量创建该类的实例(并且该实例被static修饰)提供该类公共方法可以通过外界调用

3)该类中会有某些静态成员方法的返回值是该类本身(InetAddress类:表示互联网协议(IP)地址)

5.InetAddress类:表示互联网协议(IP)地址

常用方法:

1)String getHostAddress()返回 IP 地址字符串(以文本表现形式

2)byte[] getAddress()返回此InetAddress 对象的原始 IP 地址

6.Socket编程

包括两种:TCP和UDP编程,两端必须有socket对象,还必须有IP地址和端口号

二.UDP编程

发送端(Send):

1.创建UDP协议发送端的Socket对象(DatagramSocket()):用来发送和接收数据包的套接字

2.创建数据包(通过这个数据包将数据发送到接收端):public DatagramPacket(byte[] buf, int length ,InetAddress address,int port)

3.调用UDP协议发送端发送的方法

4.关闭资源

接收端(Receive):

1.创建接收端的Socket对象(DatagramSocket())

2.创建一个数据包接收发送端发来的数据包

3.接收数据,调用DateSocket类中的接收方法:阻塞式,等待发送端发送数据,没有数据就一直等待

4.解析数据包里面的实际数据,显示在控制台上

5.关闭资源

package udp2;import java.net.DatagramPacket;import java.net.DatagramSocket;import java.net.InetAddress;//import java.net.SocketException;//import java.net.UnknownHostException;/**发送端: * 1.创建UDP协议发送端的socket对象(DatagramSocket()) * 2.创建数据包:通过数据包将数据发送到接收端:public DatagramPacket(byte[] buf,int length,InetAddress address,int port) * 3.调用UDP协议发送方法 * 4.关闭资源 */public class SendDemo {public static void main(String[] args) throws Exception {//1.创建UDP协议发送端的socket对象(DatagramSocket())DatagramSocket ds = new DatagramSocket();//2.创建数据包public DatagramPacket(byte[] buf,int length,InetAddress address,int port)byte[] bys = "hello udp".getBytes();DatagramPacket  dp = new DatagramPacket(bys,bys.length,InetAddress.getByName("192.168.1.131"),666);//3.调用UDP协议发送方法ds.send(dp);//4.关闭资源ds.close();}}
package udp2;import java.io.IOException;import java.net.DatagramPacket;import java.net.DatagramSocket;//import java.net.SocketException;/**接收端: * 1.创建接收端的Socket对象 * 2.创建一个数据包接收发送端发来的数据报包(接收容器) * 3.接收数据,调用DateSocket类中的接收方法来接收数据包 * 4.解析数据包里面的实际数据,显示在控制台上 * 5.关闭资源 */public class ReceiveDemo {public static void main(String[] args) throws IOException {//1.创建接收端的Socket对象DatagramSocket ds = new DatagramSocket(666);//2.创建一个数据包接收发送端发来的数据报包(接收容器)byte[] bys = new byte[1024];DatagramPacket dp = new DatagramPacket(bys,bys.length);//3.接收数据ds.receive(dp);//4.解析数据并显示在控制台上String ip = dp.getAddress().getHostAddress();//获取缓冲区中的实际数据byte[] dataBys = dp.getData();//获取实际缓冲区的数据的长度int len = dp.getLength();String s = new String(dataBys,0,len);//输出到控制台System.out.println(ip+"传输的数据是:"+s);//关闭资源ds.close();}}
键盘录入的两种方式:

1.Scanner类

2.BufferedReader类(字符缓冲流)特有功能 readLine():一次读取一行

BufferedReader br = new BufferedReader(new InputStreamReader(system.in));

对以上的发送端进行优化,发送端的数据来源是不停的键盘录入

package udp3;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.net.DatagramPacket;import java.net.DatagramSocket;import java.net.InetAddress;//import java.net.SocketException;public class SendDemo {public static void main(String[] args) throws IOException {//1.创建UDP协议发送端的socket对象(DatagramSocket())DatagramSocket ds = new DatagramSocket();//2.创建数据包public DatagramPacket(byte[] buf,int length,InetAddress address,int port//字符缓冲流BufferedReader br = new BufferedReader(new InputStreamReader(System.in));//一次读取一行String line = "null";while((line=br.readLine())!=null){//发送端不停发送的结束条件if("886".equals(line)){break;}//创建数据包byte[] bys = line.getBytes();DatagramPacket dp = new DatagramPacket(bys, bys.length,InetAddress.getByName("192.168.1.131"),888);//3.调用UDP协议发送方法ds.send(dp);}//4.释放资源ds.close();}}
package udp3;//import java.io.IOException;import java.net.DatagramPacket;import java.net.DatagramSocket;//import java.net.InetAddress;import java.net.SocketException;public class ReceiveDemo {public static void main(String[] args) throws SocketException,Exception {// 1.创建接收端的Socket对象DatagramSocket ds = new DatagramSocket(888);while(true){//2.创建接收容器//创建字符缓冲区byte[] bys = new byte[1024];DatagramPacket dp = new DatagramPacket(bys, bys.length);//3.接收数据ds.receive(dp);//4.解析数据//获取发送端的IP地址String ip = dp.getAddress().getHostAddress();//获取实际缓冲区的数据byte[]  dataBys = dp.getData();//实际缓冲区的长度int len = dp.getLength();String s = new String(dataBys, 0, len);//显示到控制台上System.out.println(ip+"发送了数据:"+s);//5.释放资源:由于模范一直发送的数据,所以不用释放//ds.close();}}}
接收端和发送端是在两个窗口中显示的,如何让这两个接收端和发送端处于一个窗口下(main中)

package udprunnable;import java.net.DatagramSocket;import java.net.SocketException;public class ChatRoom {/** * 需求:接收端和发送端是在两个窗口中显示的,如何让这两个接收端和发送端处于一个窗口下(main中) * (使用多线程第二种方式:Runable接口的方式实现 发送端和接收端处于一个主线程中) */public static void main(String[] args) {//创建发送端和接收端的Socket对象try {DatagramSocket sendSocket = new DatagramSocket();DatagramSocket receiveSocket = new DatagramSocket(888);//创建资源对象SendThread st = new SendThread(sendSocket);ReceiveThread rt = new ReceiveThread(receiveSocket);//创建线程类对象Thread t1 = new Thread(st);Thread t2 = new Thread(rt);//启动线程t1.start();t2.start();} catch (SocketException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}
package udprunnable;import java.io.BufferedReader;//import java.io.IOException;import java.io.InputStreamReader;import java.net.DatagramPacket;import java.net.DatagramSocket;import java.net.InetAddress;//import java.net.UnknownHostException;public class SendThread implements Runnable{private DatagramSocket ds;public SendThread(DatagramSocket ds) {super();this.ds = ds;}@Overridepublic void run() {try {//创建发送端Socket对象BufferedReader br = new BufferedReader(new InputStreamReader(System.in));//一行读取一个数据String line = null;while((line=br.readLine())!=null){//结束条件if("886".equals(line)){break;}//创建数据包byte[] bys = line.getBytes();DatagramPacket dp = new DatagramPacket(bys,bys.length,InetAddress.getByName("192.168.1.131"),888);//发送数据ds.send(dp);}} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}finally{//释放资源if(ds!=null){ds.close();}}}}
package udprunnable;import java.io.IOException;import java.net.DatagramPacket;import java.net.DatagramSocket;public class ReceiveThread implements Runnable{private DatagramSocket ds;public ReceiveThread(DatagramSocket ds) {super();this.ds = ds;}@Overridepublic void run() {try {while(true){//创建接收容器byte[] bys = new byte[1024];DatagramPacket dp = new DatagramPacket(bys, bys.length);//接收数据ds.receive(dp);//解析数据String ip = dp.getAddress().getHostAddress();//获取实际缓冲区的数据byte[] dateBys = dp.getData();//实际实际缓冲区数据的长度int len = dp.getLength();String s = new String(dateBys,0,len);System.out.println(ip+"发送的数据是"+s);}//接收要不停接收数据,不需要关闭} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}
三.TCP编程

客户端步骤:

1.创建客户端的Socket对象(Socket)

2.获取通道内的流(输出流)

3.使用输出流写数据

4.关闭客户端的Socket对象

服务器端步骤:

1.创建服务器端的Socket对象(ServerSocket)

2.服务器端需要监听客户端的连接

public Socket accept() throws IOException

3.获取通道内的输入流

4.将客户端发送的数据显示在控制台上

package tcp;import java.io.IOException;//import java.io.InputStream;import java.io.OutputStream;import java.net.Socket;import java.net.UnknownHostException;public class ClientDemo {/**客户端 * 1.创建客户端的Socket对象 * 2.获取通道内的输出流 * 3.使用输出流写数据 * 4.关闭客户端的流 * @throws IOException  * @throws UnknownHostException  *  *  */public static void main(String[] args) throws UnknownHostException, IOException {//1.创建客户端的Socket对象Socket s = new Socket("192.168.10.136",8888);//2.获取通道内的输出流OutputStream out = s.getOutputStream();//3.使用输出流写数据out.write("hello TCP".getBytes());//4.关闭客户端的流s.close();}}
package tcp;import java.io.IOException;import java.io.InputStream;import java.net.InetAddress;import java.net.ServerSocket;import java.net.Socket;public class ServerDemo {/**服务器端: * 1.创建服务器端的socket对象 * 2.监听服务器端的连接 * 3.获取通道内的输入流 * 4.将客户端的数据显示在控制台上 * @param args * @throws IOException  */public static void main(String[] args) throws IOException {// 1.创建服务器端的socket对象ServerSocket ss = new ServerSocket(8888); //2.监听服务器端的连接Socket s = ss.accept();//3.获取通道内的输入流InputStream in = s.getInputStream();//4.将客户端的数据显示在控制台上byte[] bys = new byte[1024];int len = in.read(bys);String str = new String (bys,0,len);//获取主机的IP地址InetAddress address = s.getInetAddress();String ip = address.getHostAddress();System.out.println(ip+"发送的数据是:"+str);//关闭服务器s.close();//关闭掉侦听的客户端所在的通道内的对象(Socket)ss.close();}}
改进版1:互相加入反馈

package tcp2;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.net.Socket;import java.net.UnknownHostException;public class CilentDemo {/** * @param args * @throws IOException  * @throws UnknownHostException  */public static void main(String[] args) throws UnknownHostException, IOException {//1.创建客户端的Socket对象Socket s = new Socket("192.168.1.131",888);//2.获取通道内的输出流OutputStream out = s.getOutputStream();//3.使用输出流写数据out.write("hello TCP".getBytes());//获取到服务器反馈的数据//获取通道内的输入流数据InputStream in = s.getInputStream();byte[] bys = new byte[1024];int len = in.read(bys);//读取服务器端发送来的实际字节数(阻塞式)//显示服务器端反馈的数据String client = new String(bys,0,len);System.out.println("client:"+client);//4.关闭客户端的流s.close();}}
package tcp2;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.net.ServerSocket;import java.net.Socket;public class ServerDemo {/** * @param args * @throws IOException  */public static void main(String[] args) throws IOException {// 1.创建服务器端的socket对象ServerSocket ss = new ServerSocket(888); System.out.println("正在等待客户端连接...");//2.监听服务器端的连接Socket s = ss.accept();//阻塞式方法结束System.out.println("该客户端已连接...");//3.获取通道内的输入流InputStream in = s.getInputStream();//4.将客户端的数据显示在控制台上byte[] bys = new byte[1024];int len = in.read(bys);String server = new String (bys,0,len);//输出客户端发送的数据System.out.println("server"+server);//服务器反馈//获取通道内的输出流OutputStream out = s.getOutputStream();out.write("已收到来自客户端的消息".getBytes());//关闭资源s.close();//关闭掉侦听的客户端所在的通道内的对象(Socket)ss.close();}}
改进版2:客户端键盘录入数据,服务器端将数据显示在控制台上

注意通道内的流是字节流,所以要封通道内的流

package tcp3;import java.io.BufferedReader;import java.io.BufferedWriter;import java.io.IOException;import java.io.InputStreamReader;import java.io.OutputStreamWriter;import java.net.Socket;import java.net.UnknownHostException;public class ClientDemo {/** * 客户端键盘录入消息 * @param args * @throws IOException  * @throws UnknownHostException  */public static void main(String[] args) throws  IOException {//创建客户端的Socket对象Socket s = new Socket("192.168.1.131",888);//键盘录入数据(IO流的形式)//字符流封装数据BufferedReader br = new BufferedReader(new InputStreamReader(System.in));//String str = br.readLine();//封装通道内的流(要发送的数据)BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));//一次读取一行数据String line = null;while((line=br.readLine())!=null){//键盘录入一行数据,就把一行数据封装到通道内的流中//自定义结束条件if("over".equals(line)){break;}bw.write(line);bw.newLine();bw.flush();}//关闭资源s.close();}}
package tcp3;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.net.ServerSocket;import java.net.Socket;public class ServerDemo {/** * @param args * @throws IOException  */public static void main(String[] args) throws IOException {// 1.创建服务器端的socket对象ServerSocket ss = new ServerSocket(888); System.out.println("正在等待客户端连接...");//2.监听服务器端的连接Socket s = ss.accept();//阻塞式方法结束System.out.println("该客户端已连接...");//3.封装服务器通道内的流BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));//一次读取一行数据String line = null;while((line=br.readLine())!=null){//输出数据System.out.println(line);}s.close();ss.close();}}
改进版3 客户端键盘录入,服务器端输出一个文件

客户端同版本2,以下是服务器端

package tcp4;import java.io.BufferedReader;import java.io.BufferedWriter;import java.io.FileWriter;import java.io.IOException;import java.io.InputStreamReader;import java.net.ServerSocket;import java.net.Socket;public class ServerDemo {/** * @param args * @throws IOException  */public static void main(String[] args) throws IOException {// 1.创建服务器端的socket对象ServerSocket ss = new ServerSocket(888); System.out.println("正在等待客户端连接...");//2.监听服务器端的连接Socket s = ss.accept();//阻塞式方法结束System.out.println("该客户端已连接...");//3.封装服务器通道内的流BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));//4.服务器端输出一个文本文件BufferedWriter bw = new BufferedWriter(new FileWriter("a.txt"));//服务器端通道内的流读取客户端的发送数据String line = null;while((line=br.readLine())!=null){//写入到文本中bw.write(line);bw.newLine();bw.flush();}s.close();bw.close();ss.close();}}
改进版4 客户端文本文件,服务器端显示在控制台上

服务器端同版本2,以下是客户端

package tcp5;import java.io.BufferedReader;import java.io.BufferedWriter;import java.io.FileReader;import java.io.IOException;import java.io.OutputStreamWriter;import java.net.Socket;import java.net.UnknownHostException;public class ClientDemo {/** * 客户端录入文本文件 * @param args * @throws IOException  * @throws UnknownHostException  */public static void main(String[] args) throws  IOException {//创建客户端的Socket对象Socket s = new Socket("192.168.1.131",888);//读取文本文件的内容//字符流封装数据BufferedReader br = new BufferedReader(new FileReader("a.txt"));//String str = br.readLine();//封装通道内的流(要发送的数据)BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));//一次读取一行数据String line = null;while((line=br.readLine())!=null){//键盘录入一行数据,就把一行数据封装到通道内的流中bw.write(line);bw.newLine();bw.flush();}//关闭资源br.close();s.close();}}
改进版5  客户端是文本文件,服务器端将文本文件的内容复制到一个新的文本文件中

客户端同版本4,服务器端如下:

package tcp6;import java.io.BufferedReader;import java.io.BufferedWriter;import java.io.FileWriter;import java.io.IOException;import java.io.InputStreamReader;import java.net.ServerSocket;import java.net.Socket;public class ServerDemo {/** * @param args * @throws IOException  */public static void main(String[] args) throws IOException {// 1.创建服务器端的socket对象ServerSocket ss = new ServerSocket(888); System.out.println("正在等待客户端连接...");//2.监听服务器端的连接Socket s = ss.accept();//阻塞式方法结束System.out.println("该客户端已连接...");//3.封装服务器通道内的流BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));//将通道流中的数据写到文本文件中BufferedWriter bw = new BufferedWriter(new FileWriter("newB.txt"));//一次读取一行数据String line = null;while((line=br.readLine())!=null){//输出数据bw.write(line);bw.newLine();bw.flush();}//关闭资源s.close();bw.close();ss.close();}}
改进版本6 客户端是图片文件,服务器端输出一个图片文件,并且给出反馈

图片:以字节缓冲流的方式读写(BufferedInputStream、BufferedOutputStream)

package tcpimg;import java.io.BufferedInputStream;import java.io.BufferedOutputStream;import java.io.FileInputStream;import java.io.IOException;import java.io.InputStream;import java.net.Socket;/** *客户端的图片文件,服务器端输出一个图片文件并且给出反馈 *2017年12月13日  */public class ClientDemo {public static void main(String[] args) throws IOException {// 创建客户端Socket对象Socket s = new Socket("192.168.1.131",888);//先封装文件BufferedInputStream bis = new BufferedInputStream(new FileInputStream("山里.jpg")) ;//获取通道内的流BufferedOutputStream bos = new BufferedOutputStream(s.getOutputStream());//读取图片信息,一次读取一个字节数组byte[] bys = new byte[1024];int len = 0;while((len = bis.read(bys))!=-1){//读取字节到输出流中bos.write(bys,0,len);bos.flush();}//客户端需要给服务器提供一个终止,告诉服务器端我没有数据了s.shutdownOutput();//客户端读取服务器端的反馈InputStream is = s.getInputStream();byte[] bys2 = new byte[1024];int len2 = is.read(bys2);System.out.println(new String(bys2,0,len2));//关闭资源bis.close();s.close();}}
package tcpimg;import java.io.BufferedInputStream;import java.io.BufferedOutputStream;import java.io.FileOutputStream;import java.io.IOException;import java.io.OutputStream;import java.net.ServerSocket;import java.net.Socket;public class ServerDemo {public static void main(String[] args) throws IOException {//创建服务器端Socket对象ServerSocket ss = new ServerSocket(888); //监听客户端连接Socket s = ss.accept();//封装通道内的流BufferedInputStream bis = new BufferedInputStream(s.getInputStream());//输出图片文件BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("山理.jpg"));//一次读取一个字节数组byte[] bys = new byte[1024];int len = 0;while((len=bis.read(bys))!=-1){bos.write(bys, 0, len);bos.flush();}//服务器端给客户端反馈OutputStream out = s.getOutputStream();out.write("文件上传成功".getBytes());//释放资源bos.close();s.close();ss.close();}}