java基础-网络编程

1.网络模型:

OSI参考模型、TCP/IP参考模型


数据传输的过程:向下走:封包    向上走:拆包     

向上走一直拆包,直到得到数据。

2.网络通讯要素

ip地址、端口号、传输协议

Ip和端口用来找对方,确认对方身份。协议保证双方都能听懂双方的对话,常见的传输协议是:TCP、UDP

更多网络信息参考网络相关书籍和教程。

3.常用类InetAddress,此类表示互联网协议 (IP) 地址

得到InetAddress对象的几种方法:得到本地Host;通过ip;通过域名

public static void main(String[] args) throws Exception {
		//1.通过InetAddress.getLocalHost()得到本机InetAddress对象	
		/*InetAddress host = InetAddress.getLocalHost();//主机名+ip
		System.out.println(host);//Lenovo-PC/192.168.159.10   主机名+ip
		System.out.println(host.getHostAddress());//ip
		System.out.println(host.getHostName());// 主机名
		*/
		
		//2.通过InetAddress的静态方法,传入ip得到InetAddress对象		
		/*InetAddress host = InetAddress.getByName("192.168.159.1");
		System.out.println(host.getHostAddress());//ip
		System.out.println(host.getHostName());//主机名
               */
		
		//3.通过域名得到InetAddress对象数组
		 InetAddress[] is = InetAddress.getAllByName("www.baidu.com");
	         System.out.println(is.length);//2
	         System.out.println(is[0].getHostName());//www.baidu.com 得到域名
	         System.out.println(is[1].getHostName());
	}

TCP、UDP、Socket

1.TCP与UDP的区别

(1)TCP

建立连接,形成传输数据的通道;在连接中进行大数据量传输;通过三次握手完成连接,是可靠协议;必需建立连接,所以效率低。

(2)UDP

将数据,源和目的封装成包,不需要建立连接;每个数据报的大小限制在64K内;因为不需要建立连接,所以是不可靠的传输;不需要建立连接,所以速度快。

2.Socket

Socket是为网络服务提供的一种机制;通信两段都有Socket,网络通信实际上就是Socket通信;数据在Socket间的通信是通过IO实现的。

3.UDP传输

(1)UDP收发数据使用的是DatagramSocket。数据需要封装成包DatagramPacket,需要建立发送端和接收端,这两个端是相互独立的程序。

(2)InetAddress/SocketAddress区别

InetAddress指的是IPSocketAddress是封装了ip和端口的抽象类

(3)网络编程使用的包是java.net。一般net需要和io包一起使用。

(4)建立服务连接的DatagramSocket的创建不放在while中,会发生绑定异常.建立Socket相当于建立连接,连接只需要建立一次,如果没有断开又建立连接也会发生异常,所以建立连接Socket的创建是唯一的。

(5)因为UDP传输的两端是相互独立的程序,所以要建立两个main,启动的时候先启动接收端,再启动发送端。

(6)发送端Socket可以关闭,一般接收端Socket不用关闭

键盘发送数据的例子:

发送端要指明接收端的ip,端口。发送端的端口是随机分配的,也可以自己指定.接收端要指明接收的端口号,接收端除了可以获得数据,还可以得到发送端的ip,端口。

自己指定发送端端口号:

DatagramSocket ds = new DatagramSocket(8888);
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
(**)发送端是键盘输入,所以不用while(true)
//发送端
public class SendClass {
	public static void main(String[] args) throws Exception {
		DatagramSocket ds = new DatagramSocket();
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		String line = null;
		while((line = br.readLine())!= null){//readLine是一个阻塞式的方法
			if("over".equals(line)){
				break;
			}
			byte[] b = line.getBytes();
			DatagramPacket dp = new DatagramPacket(b,b.length,InetAddress.getByName("127.0.0.1"),10001);
			ds.send(dp);
		}
        ds.close();
	}
}
(**)接收端需要进行while(true),接收端的连接不用关闭
import java.net.DatagramPacket;
import java.net.DatagramSocket;

//接收端
public class ReciveClass {
	public static void main(String[] args) throws Exception{
         //指明用哪个端口接收
		DatagramSocket ds = new DatagramSocket(10001);
                //接收端一般就是一直的while(true)
		while(true){
			byte[] b = new byte[1024];
			DatagramPacket dp = new DatagramPacket(b,b.length);
			ds.receive(dp);
			//打印接收到的发送端的数据
			String ip = dp.getAddress().getHostAddress();//打印发送端的ip
			String data = new String(dp.getData(),0,dp.getLength());//打印发送端的数据
			int port = dp.getPort();//打印发送端的端口
			System.out.println("ip:"+ip+",data:"+data+",port:"+port);	
		}
	}
}

使用线程键盘发送数据的例子:(注意:是单独的程序)

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;


public class Send implements Runnable {
	DatagramSocket ds = null;
	public Send(DatagramSocket ds){
		this.ds = ds;
	}
	@Override
	public void run() {
		try{
			BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
			String line = null;
			while((line = br.readLine())!= null){//readLine是一个阻塞式的方法
				if("over".equals(line)){//但是发送端结束了,接收端还会一直接收,阻塞着
					break;
				}
				byte[] b = line.getBytes();
				DatagramPacket dp = new DatagramPacket(b,b.length,InetAddress.getByName("127.0.0.1"),10002);
				ds.send(dp);
			}
			
		}catch(Exception e){
			throw new RuntimeException("发送端失败");
		}finally{ds.close();}
	}

}
import java.net.DatagramPacket;
import java.net.DatagramSocket;


public class Recive implements Runnable {
	DatagramSocket ds = null;
	public Recive(DatagramSocket ds){
		this.ds = ds;
	}
	@Override
	public void run() {
		try{
			while(true){
				byte[] b = new byte[1024];
				DatagramPacket dp = new DatagramPacket(b,b.length);
				ds.receive(dp);
				//打印接收到的发送端的数据
				String ip = dp.getAddress().getHostAddress();//打印发送端的ip
				String data = new String(dp.getData(),0,dp.getLength());//打印发送端的数据
				int port = dp.getPort();//打印发送端的端口
				System.out.println("ip:"+ip+",data:"+data+",port:"+port);	
			}
		}catch(Exception e){
			throw new RuntimeException("接收端失败");
		}
	}

}
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class Test{

	public static void main(String[] args) throws Exception {
		DatagramSocket sendS = new DatagramSocket();//发送端与接收端使用的Socket是不同的,两端各自有一个
		DatagramSocket reciveS = new DatagramSocket(10002);
		new Thread(new Send(sendS)).start();
		new Thread(new Recive(reciveS)).start();
    }
}

4.TCP传输

(1)需要客户端和服务端,是两个独立的程序。客户端使用Socket,服务端使用ServerSocket。通过Socket中的IO进行数据传输。

(2)客户端需要指明服务端接收端的Ip与端口号。服务端需要指明接受的端口号。

(3)接受的服务端可以得到客户端的ip

(4)通过Socket可以得到 InputStream和OutputStream

(5)先启动服务端,然后启动客户端

客户端发送,服务端接收:

import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;


public class TcpServer {
	public static void main(String[] args) throws Exception{
		ServerSocket ss = new ServerSocket(10003);
		Socket s = ss.accept();//获得客户端的Socket
		String ip = s.getInetAddress().getHostAddress();
		System.out.println(ip+"....connection");
		InputStream in = s.getInputStream();
		byte[] b = new byte[1024];
		int count = in.read(b);
		String str = new String(b,0,count);
		System.out.println(str);
		
		//只关闭Socket和ServerSocket
		s.close();
		ss.close();
	}
}
import java.io.OutputStream;
import java.net.Socket;

//客户端
public class TcpClient {
	public static void main(String[] args) throws Exception{
		//指明目的的ip和端口
		Socket s = new Socket("127.0.0.1",10003);
		OutputStream os = s.getOutputStream();
		os.write("hello".getBytes());
		
		//只关闭Socket
		s.close();
	}
}

客户端与服务端互相读写:

import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class TcpServer {
	public static void main(String[] args) throws Exception{
		ServerSocket ss = new ServerSocket(10004);
		Socket s = ss.accept();//获得客户端的Socket
		String ip = s.getInetAddress().getHostAddress();
		System.out.println(ip+"....connection");
		
		//读取
		InputStream in = s.getInputStream();
		byte[] b = new byte[1024];
		int count = in.read(b);
		String str = new String(b,0,count);
		System.out.println("服务端接收的数据:"+str);
		
		OutputStream out = s.getOutputStream();
		out.write("这是服务端写的数据".getBytes());
		
		//只关闭Socket和ServerSocket
		s.close();
		ss.close();
	}
}
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

//客户端
public class TcpClient {
	public static void main(String[] args) throws Exception{
		//指明目的的ip和端口
		Socket s = new Socket("127.0.0.1",10004);
		
		//写过去
		OutputStream os = s.getOutputStream();
		os.write("这是客户端写的数据".getBytes());
		
		
		//进行读取
		InputStream in = s.getInputStream();
		byte[] b = new byte[1024];
		int count = in.read(b);
		String str = new String(b,0,count);
		System.out.println("从服务端读到的数据:"+str);
		
		//只关闭Socket
		s.close();
	}
}

使用Buffered提高效率,从键盘读取,客户端与服务端进行数据读写:

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;

public class TcpServer {
	public static void main(String[] args) throws Exception{
		ServerSocket ss = new ServerSocket(10005);
		Socket s = ss.accept();//获得客户端的Socket
		String ip = s.getInetAddress().getHostAddress();
		System.out.println(ip+"....connection");
		
		//读取,从客户端读取
		BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
		//写,写入客户端
		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
		
		String str = null;
		while((str = br.readLine())!= null){
			bw.write(str.toUpperCase());
			//注意:下面的两行一定要写,因为readLine没有换行符
			bw.newLine();
			bw.flush();
		}
		
		//不需要关闭流
		//只关闭Socket和ServerSocket
		s.close();
		ss.close();
	}
}
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;

//客户端
public class TcpClient {
	public static void main(String[] args) throws Exception{
		//指明目的的ip和端口
		Socket s = new Socket("127.0.0.1",10005);
		//从键盘读
		BufferedReader brJian = new BufferedReader(new InputStreamReader(System.in));	
		//写过去,写到服务端去
		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));	
		//读取,从服务端读取
		BufferedReader brFu = new BufferedReader(new InputStreamReader(s.getInputStream()));	
		String line = null;
		while((line = brJian.readLine())!=null){
			//控制从键盘读取会结束的
			if("over".equals(line)){
				break;
			}
			bw.write(line);
			//注意:下面的两行一定要写,因为readLine没有换行符
			bw.newLine();
			bw.flush();
			//注意:从服务端读是写在这里的,写在了while中,实时通讯
			String str = brFu.readLine();
			System.out.println("客户端读到的数据:"+str);
		}
		
		//只关闭Socket
		s.close();
		//关闭键盘读取的流
		brJian.close();
	}
}

使用PrintWriter,优于Buffered:

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

public class TcpServer {
	public static void main(String[] args) throws Exception{
		ServerSocket ss = new ServerSocket(10005);
		Socket s = ss.accept();//获得客户端的Socket
		String ip = s.getInetAddress().getHostAddress();
		System.out.println(ip+"....connection");
		
		//读取,从客户端读取
		BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
		//写,写入客户端
		//BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
		PrintWriter bw = new PrintWriter(s.getOutputStream());
		
		String str = null;
		while((str = br.readLine())!= null){
			bw.println(str.toUpperCase());
			bw.flush();//需要刷新
			//也可以在创建PrintWriter的时候指明会自动刷新
		}
		
		//不需要关闭流
		//只关闭Socket和ServerSocket
		s.close();
		ss.close();
	}
}

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;

//客户端
public class TcpClient {
	public static void main(String[] args) throws Exception{
		//指明目的的ip和端口
		Socket s = new Socket("127.0.0.1",10005);
		//从键盘读
		BufferedReader brJian = new BufferedReader(new InputStreamReader(System.in));
		//写过去,写到服务端去
		//BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
		PrintWriter bw = new PrintWriter(s.getOutputStream());
		//读取,从服务端读取
		BufferedReader brFu = new BufferedReader(new InputStreamReader(s.getInputStream()));
		
		String line = null;
		while((line = brJian.readLine())!=null){
			//控制从键盘读取会结束的
			if("over".equals(line)){
				break;
			}
			bw.println(line);
			bw.flush();
			//注意:从服务端读是写在这里的,写在了while中,实时通讯
			String str = brFu.readLine();
			System.out.println("客户端读到的数据:"+str);
		}
		
		//只关闭Socket
		s.close();
		//关闭键盘读取的流
		brJian.close();
	}
}

上面程序可能存在的问题:客户端从键盘读,有结束的时候,写过去有结束的时候,但是服务端读没有结束的时候,就会造成阻塞。后面讲解决的办法。

文件复制(Buffered、PrintWriter):

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

public class TcpServer {
	public static void main(String[] args) throws Exception{
		ServerSocket ss = new ServerSocket(10006);
		Socket s = ss.accept();//获得客户端的Socket
		String ip = s.getInetAddress().getHostAddress();
		System.out.println(ip+"....connection");
		
		//读取,从客户端读取
		BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
		//写,写入客户端
		PrintWriter bw = new PrintWriter(s.getOutputStream(),true);
		//写入文件,文件不存在的时候会自动的创建
		PrintWriter pw = new PrintWriter(new FileWriter("C:\\Users\\huer\\Desktop\\b.txt"),true);
		
		String str = null;
		while((str = br.readLine())!= null){
			pw.println(str);	
		}
		
		//这里需要写在循环的外面
		bw.println("服务端说:上传成功");
		
		//不需要关闭流
		//只关闭Socket和ServerSocket
		s.close();
		ss.close();
		pw.close();
	}
}
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;

//客户端
public class TcpClient {
	public static void main(String[] args) throws Exception{
		//指明目的的ip和端口
		Socket s = new Socket("127.0.0.1",10006);
		
		//从文件读
		BufferedReader brJian = new BufferedReader(new FileReader("C:\\Users\\huer\\Desktop\\a.txt"));
		
		//写过去,写到服务端去
		PrintWriter bw = new PrintWriter(s.getOutputStream(),true);
		
		//读取,从服务端读取
		BufferedReader brFu = new BufferedReader(new InputStreamReader(s.getInputStream()));
		
		String line = null;
		//从文件读取
		while((line = brJian.readLine())!=null){			
			bw.println(line);			
		}
		
		//这个是写在循环外的
		String str = brFu.readLine();
		System.out.println("客户端读到的数据:"+str);
		
		//只关闭Socket
		s.close();
		//关闭文件流
		brJian.close();
	}
}

读写都是对应着的。

分析存在的问题:客户端从文件读,有结束的时候,所以写到服务端有结束的时候,但是服务端还在一直等着接收客户端传过来的数据,会一直等着,不知道什么时候结束,所以服务端存在方法阻塞的情况。

shutdownOutput()方法解决方法阻塞:

客户端写结束的时候,指明结束写

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

public class TcpServer {
	public static void main(String[] args) throws Exception{
		ServerSocket ss = new ServerSocket(10006);
		Socket s = ss.accept();//获得客户端的Socket
		String ip = s.getInetAddress().getHostAddress();
		System.out.println(ip+"....connection");
		
		//读取,从客户端读取
		BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
		//写,写入客户端
		PrintWriter bw = new PrintWriter(s.getOutputStream(),true);
		//写入文件,文件不存在的时候会自动的创建
		PrintWriter pw = new PrintWriter(new FileWriter("C:\\Users\\huer\\Desktop\\b.txt"),true);
		
		String str = null;
		while((str = br.readLine())!= null){
			pw.println(str);	
		}
		
		//这里需要写在循环的外面
		bw.println("服务端说:上传成功");
		
		//不需要关闭流
		//只关闭Socket和ServerSocket
		s.close();
		ss.close();
		pw.close();
	}
}
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;

//客户端
public class TcpClient {
	public static void main(String[] args) throws Exception{
		//指明目的的ip和端口
		Socket s = new Socket("127.0.0.1",10006);
		
		//从文件读
		BufferedReader brJian = new BufferedReader(new FileReader("C:\\Users\\huer\\Desktop\\a.txt"));
		
		//写过去,写到服务端去
		PrintWriter bw = new PrintWriter(s.getOutputStream(),true);
		
		//读取,从服务端读取
		BufferedReader brFu = new BufferedReader(new InputStreamReader(s.getInputStream()));
		
		String line = null;
		//从文件读取
		while((line = brJian.readLine())!=null){			
			bw.println(line);			
		}
		s.shutdownOutput();//指明结束写
		//这个是写在循环外的
		String str = brFu.readLine();
		System.out.println("客户端读到的数据:"+str);
		
		//只关闭Socket
		s.close();
		//关闭文件流
		brJian.close();
	}
}

下面是一个解决方法阻塞的例子:

import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class TcpServer {
	public static void main(String[] args) throws Exception{
		ServerSocket ss = new ServerSocket(10007);
		Socket s = ss.accept();
		String ip = s.getInetAddress().getHostAddress();
		System.out.println(ip+"....connection");
		FileOutputStream fo = new FileOutputStream("C:\\Users\\huer\\Desktop\\图片\\2.jpg");
		
		//从文件读,上传到另一个图片
		byte[] b = new byte[1024];
		int len = 0;
		InputStream in = s.getInputStream();
		while((len = in.read(b))!=-1){
			fo.write(b, 0, len);
		}
		
		OutputStream oos = s.getOutputStream();
		oos.write("上传成功".getBytes());
		
		s.close();
		ss.close();
		fo.close();
	}
}
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

//客户端
public class TcpClient {
	public static void main(String[] args) throws Exception{
		Socket s = new Socket("127.0.0.1",10007);
		//文件
		FileInputStream fi = new FileInputStream("C:\\Users\\huer\\Desktop\\图片\\1.jpg");
		OutputStream os = s.getOutputStream();
		
		//从文件读,写过去
		byte[] b = new byte[1024];
		int len = 0;
		while((len = fi.read(b))!=-1){
            //读文件有结束的时候,所以写过去有结束的时候,但是服务端不知道,所以下面用shutdownOutput指明写入结束
			os.write(b, 0, len);
		}
		s.shutdownOutput();//关闭输出流
		//从服务端读,打印出来
		InputStream in = s.getInputStream();
		byte[] bin = new byte[1024];
		int blen = 0;
		blen = in.read(bin);
		System.out.println(new String(bin,0,blen));
		
		//关闭连接和文件流
		s.close();
		fi.close();
	}
}
使用线程实现TCP传输:


思路:服务端的ServerSocket只能初始化一次,然后只要有一个客户端连接上来,就有一个Socket,就启动一个线程。

服务端ServerSocket不用关闭。

使用线程实现图片文件上传。客户端从本地文件一直读取图片并上传至服务端,服务端将读取到的图片保存起来。

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;


public class PicServer {
	public static void main(String[] args) throws Exception{
		ServerSocket ss = new ServerSocket(10007);
		//允许多个人连接进来,使用while
		while(true){
			Socket s = ss.accept();
			new Thread(new PicThread(s)).start();
		}
		//ss.close();//不用进行关闭
	}
}
class PicThread implements Runnable{

	private Socket s;
	PicThread(Socket s){
		this.s = s;
	}
	@Override
	public void run() {
		int count = 1;
		String ip = s.getInetAddress().getHostAddress();
		try{
			System.out.println(ip+"....connection");
			//用File封装一下
			//File f = new File("C:\\Users\\huer\\Desktop\\图片\\2.jpg");
			File f = new File("C:\\Users\\huer\\Desktop\\图片\\"+ip+"("+count+")"+".jpg");
			
			//这是避免文件名覆盖
			if(f.exists()){
				//这里使用的是++count,不要使用count++
				f = new File("C:\\Users\\huer\\Desktop\\图片\\"+ip+"("+(++count)+")"+".jpg");
			}
			System.out.println(count);
			FileOutputStream fo = new FileOutputStream(f);//不存在的时候会自动创建
			
			//从文件读,上传到另一个图片
			byte[] b = new byte[1024];
			int len = 0;
			InputStream in = s.getInputStream();
			while((len = in.read(b))!=-1){
				fo.write(b, 0, len);
			}
			
			OutputStream oos = s.getOutputStream();
			oos.write("上传成功".getBytes());
			
			s.close();
			fo.close();
		}catch(Exception e){
			throw new RuntimeException(ip+"上传文件失败");
		}
	}
	
}
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

//客户端
public class TcpClient {
	public static void main(String[] args) throws Exception{
		Socket s = new Socket("127.0.0.1",10007);
		
		//关于图片的路径需要重新修改,现在先不管,测试的话是有问题的
		if(args.length!=1){
			System.out.println("请选择一个jpg格式的图片");
			return;
		}
		File f = new File(args[0]);
		if(!(f.exists() && f.isFile())){
			System.out.println("该文件有问题,要么不存在,要么不是文件");
			return;
		}
		if(!(f.getName().endsWith(".jpg"))){
			System.out.println("图片格式错误,请重新选择");
			return;
		}
		if(f.length()>1024*1024*5){
			System.out.println("文件过大,重新选择");
			return;
		}
		
		//文件
		FileInputStream fi = new FileInputStream(f);
		OutputStream os = s.getOutputStream();
		
		//从文件读,写过去
		byte[] b = new byte[1024];
		int len = 0;
		while((len = fi.read(b))!=-1){
			os.write(b, 0, len);
		}
		s.shutdownOutput();//关闭输出流
		//从服务端读,打印出来
		InputStream in = s.getInputStream();
		byte[] bin = new byte[1024];
		int blen = 0;
		blen = in.read(bin);
		System.out.println(new String(bin,0,blen));
		
		//关闭连接和文件流
		s.close();
		fi.close();
	}
}

用户登录次数限制:

思路:用户最多进行三次的尝试登陆,服务端也只进行三次的测试登陆,所以有一个for循环。for循环有结束控制的条件,所以不需要使用shutdownOutput()

import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;


public class PicServer {
	public static void main(String[] args) throws Exception{
		ServerSocket ss = new ServerSocket(10008);
		while(true){
			Socket s = ss.accept();
			new Thread(new PicThread(s)).start();
		}
	}
}
class PicThread implements Runnable{

	private Socket s;
	PicThread(Socket s){
		this.s = s;
	}
	@Override
	public void run() {
		int count = 1;
		String ip = s.getInetAddress().getHostAddress();
		try{
			System.out.println(ip+"....connection");
			BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
			PrintWriter pw = new PrintWriter(s.getOutputStream(),true);	
			for(int i=1;i<=3;i++){
				//这里是非常要注意的点:在循环里面,每次都要重新的打开用户名的文件,操作完一次之后就要进行关闭
				//所以brFile的创建要在for中,brFile的关闭也要在for中
				
				BufferedReader brFile = new BufferedReader(new FileReader("C:\\Users\\huer\\Desktop\\user.txt"));
				String name = br.readLine();
				if(name == null){
					break;
				}
				System.out.println(name);
				boolean f = false;
				String line = null;
				while((line =brFile.readLine())!=null){
					System.out.println("服务端从文件中读到的数据:"+line);
					if(line.equals(name)){
						f = true;
						break;
					}
				}
				if(f){
					System.out.println(name+"已登陆");
					pw.println(name+"欢迎登陆");
					break;//停止服务端的for循环
				}else{
					System.out.println(name+"尝试登陆");
					pw.println(name+"用户名不存在");
				}
				brFile.close();
			}
			
			s.close();
		}catch(Exception e){
			throw new RuntimeException(ip+"校验失败");
		}
	}
	
}
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;

//客户端
public class TcpClient {
	public static void main(String[] args) throws Exception{
		Socket s = new Socket("127.0.0.1",10008);
		BufferedReader brJian = new BufferedReader(new InputStreamReader(System.in));//从键盘读
		BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));//从服务端读
		PrintWriter pw = new PrintWriter(s.getOutputStream(),true);//向服务端写
		
		//只允许用户操作3次
		for(int i=1;i<=3;i++){
			String line = brJian.readLine();
			//防止方法 的阻塞
			if(line == null){
				break;
			}
			pw.println(line);
			String str = br.readLine();
			System.out.println("从服务端读取的信息:"+str);
			//登陆成功之后就退出循环
			if(str.contains("欢迎")){
				break;//如果读到欢迎登陆了,客户端就停止for循环
			}
		}
		
		s.close();
		brJian.close();
	}
}

浏览器-自定义服务端,访问的时候:192.168.159.10:11000,注意ip不要写loacalhost,不要写127.0.0.1:

服务端:

public class ServerDemo {
	public static void main(String[] args) throws Exception{
		ServerSocket ss = new ServerSocket(11000);
		Socket s = ss.accept();
		String ip = s.getInetAddress().getHostAddress();
		System.out.println(ip+"....connection");
		//这里就是简单的测试
		//客户端连接上服务端之后,发送给客户端,"客户端你好"
		PrintWriter pw = new PrintWriter(s.getOutputStream(),true);
		//pw.println("<font color='red' size='7'>客户端,你好</font>");
		pw.println("客户端,你好");
		s.close();
		ss.close();
	}
}

浏览器-自定义服务端,服务端读取浏览器传递过来的消息头,然后给浏览器写过去一些数据:

import java.io.InputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;


public class ServerDemo {
	public static void main(String[] args) throws Exception{
		ServerSocket ss = new ServerSocket(11000);
		Socket s = ss.accept();
		String ip = s.getInetAddress().getHostAddress();
		System.out.println(ip+"....connection");
		//输出一下从浏览器读过来的信息头
		InputStream in = s.getInputStream();
		byte[] b = new byte[1024];
		int len = 0;
		len = in.read(b);
		String str = new String(b,0,len);
		System.out.println("从浏览器读到的数据:"+str);
		
		PrintWriter pw = new PrintWriter(s.getOutputStream(),true);
		pw.println("<font color='red' size='7'>客户端,你好</font>");
		//pw.println("客户端,你好");
		s.close();
		ss.close();
	}
}
从浏览器读到的数据:GET / HTTP/1.1
Host: 192.168.159.10:11000(这里就相当于客户端的Socket)
User-Agent: Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:58.0) Gecko/20100101 Firefox/58.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,en-US;q=0.8,zh;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Connection: keep-alive
Upgrade-Insecure-Requests: 1

自定义浏览器-自定义服务器,就是客户端写过去的数据首先写头消息,然后读服务端返回的数据:

自定义浏览器就是:写过去头消息,然后是数据:

import java.io.InputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

//自定义服务器
public class ServerDemo {
	public static void main(String[] args) throws Exception{
		ServerSocket ss = new ServerSocket(11000);
		Socket s = ss.accept();
		String ip = s.getInetAddress().getHostAddress();
		System.out.println(ip+"....connection");
		//输出一下从浏览器读过来的信息头
		InputStream in = s.getInputStream();
		byte[] b = new byte[1024];
		int len = 0;
		len = in.read(b);
		String str = new String(b,0,len);
		System.out.println("从浏览器读到的数据:"+str);
		
		PrintWriter pw = new PrintWriter(s.getOutputStream(),true);
		pw.println("<font color='red' size='7'>客户端,你好</font>");
		//pw.println("客户端,你好");
		s.close();
		ss.close();
	}
}
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;

//自定义浏览器
public class MyIE {
	public static void main(String[] args) throws Exception{
		Socket s = new Socket("192.168.159.10",11000);
		PrintWriter pw = new PrintWriter(s.getOutputStream(),true);
		pw.println("GET / HTTP/1.1");//"/"是请求的路径
		pw.println("Accept: */*");
		pw.println("Accept-Language: zh-CN");
		pw.println("Host: 192.168.159.10:11000");
		pw.println("Connection: keep-alive");
		pw.println("Connection: closed");
		
		//下面的两行是固定的格式
		pw.println();
		pw.println();
		
		BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
		String line = null;
		line=br.readLine();
		System.out.println(line);
	
		s.close();
	}
}

URL

封装浏览器访问的url,表示统一资源定位符。

public static void main(String[] args) throws Exception {
		URL url = new URL("http://192.168.159.10:11000/myweb/test.html?name=zhangsan&age=20");
		System.out.println(url.getProtocol());//http
		System.out.println(url.getHost());//192.168.159.10
		if(url.getPort() == -1){
			String port = "11000";
		}
		System.out.println(url.getPort());//11000
		System.out.println(url.getPath());//  /myweb/test.html
		System.out.println(url.getFile());//  /myweb/test.html?name=zhangsan&age=20
		System.out.println(url.getQuery());//  name=zhangsan&age=20
	}

URLConnection

URLConnection表示URL所引用的远程对象的连接。url.openConnection()。每次调用这个方法都会得到一个新的连接。

public static void main(String[] args) throws Exception {
		URL url = new URL("http://192.168.159.10:11000/myweb/test.html");
		URLConnection connection = url.openConnection();
		System.out.println(connection);
		InputStream in = connection.getInputStream();
		OutputStream out = connection.getOutputStream();
		//进行读写.....
		
	}









  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值