java网络编程

一.网络基础知识

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 block
			e.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;
	}

	@Override
	public 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 block
			e.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;
	}

	@Override
	public 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 block
			e.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();
		
	}
}




























评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值