Java之Socket学习笔记

网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket。建立网络通信连接至少要一对端口号(socket)。socket本质是编程接口(API),对TCP/IP的封装,TCP/IP也要提供可供程序员做网络开发所用的接口,这就是Socket编程接口;HTTP是轿车,提供了封装或者显示数据的具体形式;Socket是发动机,提供了网络通信的能力。 Java Socket(套接字)通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄。应用程序通常通过"套接字"向网络发出请求或者应答网络请求。

输入图片说明 TCP/IP 是指 TCP 和 IP 这两种协议,同时TCP属于传输层,IP属于网络层;通常使用的网络(包括互联网)是在 TCP/IP 协议族的基础上运作 的。而 HTTP 属于它内部的一个子集。 输入图片说明

端口

  • 用于区分不同应用程序
  • 端口的号范围0-65535,其中0-1023为系统所保留
  • IP地址和端口号组成了所谓的socket,socket是网络用运行的程序之间双向通信链路的终结点,是TCP和UDP的基础

Java针对网络通信的不同层次,提供四大类网络功能

  • InetAddress:用于标识网络上的硬件资源
  • URL:统一资源定位符,通过URL可以直接读取或写入网络上的数据
  • Sockets:使用TCP协议实现网络通信的Socket相关类
  • Datagram:使用UDP协议,将数据保存到数据报文中,通过网络进行通信

InetAddress

public class InetAddressDemoOne {
	public static void main(String[] args) throws UnknownHostException {
		//获取本机的InetAddress对象
		InetAddress address = InetAddress.getLocalHost();
		System.out.println("计算机名:" + address.getHostName());
		System.out.println("ip地址:" + address.getHostAddress());
		//打印InetAddress对象
		System.out.println("InetAddress对象:" + address);
		//通过主机名获取InetAddress对象
		InetAddress address1 = InetAddress.getByName("Tony");
		System.out.println("计算机名:" + address1.getHostName());
		System.out.println("ip地址:" + address1.getHostAddress());
		System.out.println("InetAddress对象:" + address1);
	}
}

代码输出结果:

计算机名:Tony
ip地址:192.168.56.1
InetAddress对象:Tony/192.168.56.1
计算机名:Tony
ip地址:192.168.56.1
InetAddress对象:Tony/192.168.56.1

URL

使用URL读取网页内容

  • 通过URL对象的openStream()方法可以得到相应资源的数据输入流
  • 通过输入流可以读取,访问网络上的数据

URL的代码使用演示:

public class UrlDemo {
	
	public void testUrlOne() throws MalformedURLException{
		URL url = new URL("http://www.baidu.com:8080");
		URL urlOne = new URL(url, "/index.html?username=tony#one");
		System.out.println("协议:" + urlOne.getProtocol());
		System.out.println("主机: " + urlOne.getHost());
		//若没有标明端口号,便会输出-1,现在标明端口号为8080,便输出8080
		System.out.println("端口:" + urlOne.getPort());
		System.out.println("文件路径:" + urlOne.getPath());
		System.out.println("文件名:" + urlOne.getFile());
        System.out.println("查询字符串:" + urlOne.getQuery());
		System.out.println("锚点位置:" + urlOne.getRef());
		
	}
	
	public void testUrlTwo() {
		try {
			URL url = new URL("http://www.baidu.com");
			//通过openStream()方法得到指定资源的输入流
			InputStream in = url.openStream();
			//通过输入流读取网络上的数据
			InputStreamReader irs = new InputStreamReader(in, "utf-8");
			BufferedReader br = new BufferedReader(irs);
			String data = br.readLine();
			while (data != null) {
				System.out.println(data);
				data = br.readLine();
			}
			br.close();
			irs.close();
			in.close();
		} catch (MalformedURLException e) {
			e.printStackTrace();
		} catch (IOException ioe) {
			ioe.printStackTrace();
		}
    }
	public static void main(String[] args) throws MalformedURLException {
		UrlDemo url = new UrlDemo();
        //URL类的基本使用
		url.testUrlOne();
        //读取网页中的内容
		url.testUrlTwo();
	}
}

testUrlOne()方法输出的结果为:

协议:http
主机: www.baidu.com
端口:8080
文件路径:/index.html
文件名:/index.html?username=tony
锚点位置:one
查询字符串:username=tony

Socket通信

TCP协议是面向连接,可靠的,有序的,以字节流的方式发送数据的

基于TCP协议实现的网络通信的类:

  • 客户端的Socket类
  • 服务器端的ServerSocket类

输入图片说明

Socket通信实现的步骤:

  1. 创建ServerSocket和Socket
  2. 打开连接到Socket的输出、输入流
  3. 按照协议对Socket进行读写操作
  4. 关闭输入输出流,关闭Socket

服务端的实现:

  1. 创建ServerSocket对象
  2. 通过accept()方法监听客户端的请求
  3. 连接建立后,通过输入流读取客户端的请求信息
  4. 通过输出流向客户端发送响应信息
  5. 关闭相关资源

客户端的实现:

  1. 创建Socket对象,指明需要连接的服务器地址
  2. 连接建立后,通过输出流向服务器端发送请求信息
  3. 通过输入流获取服务器响应的信息 4.关闭相关资源

多线程服务器实现:

  1. 服务器端创建ServerSocket,循环调用accept()
  2. 客户端创建一个socket并和服务器端连接
  3. 服务端接受客户端请求,创建一个socket与该客户连接
  4. 建立连接的两个socket在一个单独的线程上对话
  5. 服务端继续等待新的连接

客户端的事例代码:

public class Client {
	public void createScoket() {
		try {
			//1.创建客户端Socket,指定服务器的地址与端口
			Socket socket = new Socket("localhost", 8080);
			//2.获取输出流,向服务器发送信息
			OutputStream os = socket.getOutputStream();
			PrintWriter pw = new PrintWriter(os);
			pw.write("用户名:tony; 密码: 1234");
			pw.flush();
			socket.shutdownOutput();
			//3.获取输入流,获取服务器的响应信息
			InputStream is = socket.getInputStream();
			BufferedReader br = new BufferedReader(new InputStreamReader(is));
			String info = null;
			while ((info = br.readLine()) != null) {
				System.out.println("我是客户端,服务端说:" + info);
			}
			//4.关闭资源
			socket.close();
			
		} catch (UnknownHostException uhe) {
			uhe.printStackTrace();
		} catch (IOException ioe) {
			ioe.printStackTrace();
		}
	}
	public static void main(String[] args) {
		Client client = new Client();
		client.createScoket();
	}
}

多线程类的事例代码:

public class ServerThread implements Runnable {
	//和本线程相关的Socket
	private Socket socket;
	public ServerThread(Socket socket) {
		this.socket = socket;
	}
	//线程执行的操作,响应客户端的请求
	@Override
	public void run() {
		try {
			InputStream is = socket.getInputStream();
			InputStreamReader isr = new InputStreamReader(is);
			BufferedReader br = new BufferedReader(isr);
			OutputStream os = socket.getOutputStream();
			PrintWriter pw = new PrintWriter(os);
			String info ;
			while ((info = br.readLine()) != null) {
				System.out.println("我是服务器,客户端说:" + info);
			}
			socket.shutdownInput();
			pw.write("欢迎您!");
			pw.flush();
		} catch (IOException ioe) {
			ioe.printStackTrace();
		} finally {
			try {
				socket.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}

服务端的事例代码:

public class Server {
	public void createServerSocket() throws IOException {
		ServerSocket serverSocket = new ServerSocket(8080);
		Socket socket = null;
		int count = 0;
		System.out.println("***服务器即将启动,等待客户端的连接***");
		while (true) {
			socket = serverSocket.accept();
			//创建一个线程
			ServerThread servereThread = new ServerThread(socket);
			Thread thread = new Thread(servereThread);
			//启动线程
			thread.start();
			count++;
			System.out.println("客户端的数量为:" + count);
			System.out.println("当前客户端的IP:" + socket.getInetAddress().getHostAddress());
		}
	}
	public static void main(String[] args) throws IOException {
		Server  server = new Server();
		server.createServerSocket();
	}
}

UDP编程

进行数据传输时,首先需要将要传输的数据定义成数据报(Datagram),在数据报中指明数据所要送达的Socket(主机地址和端口号),然后再将数据报发送出去 UDP相关的操作类:

  • DatagramPacket:表示数据报包
  • DatagramSocket:进行端到端通信的类

服务端(客户端)实现:

  1. 创建DatagramSocket,指定端口号
  2. 创建DatagraPacket
  3. 接受客户端发送的数据信息
  4. 读取数据

客户端实现的事例代码:

public class UDPClient {
	public void createDatagramSocket() throws IOException {
		/*
		 * 向服务器发送数据
		 */
		//1.定义服务器的地址,端口,数据
		InetAddress adddress = InetAddress.getByName("localhost");
		int port = 8080;
		byte[] data = "用户名:admin;密码:123".getBytes();
		//2.创建数据报,包含发送的数据信息
		DatagramPacket packet = new DatagramPacket(data, data.length, adddress, port);
		//3.创建DatagramSocket对象
		DatagramSocket socket = new DatagramSocket();
		//4.向服务端发送数据报
		socket.send(packet);
		
		/*
		 * 接收服务器响应的数据
		 */
		//1.创建数据报,用于接收服务器的响应数据
		byte[] data2 = new byte[1024];
		DatagramPacket packet2 = new DatagramPacket(data2, data2.length);
		socket.receive(packet2);
		String reply = new String(data2, 0, packet2.getLength());
		System.out.println("我是客户端,服务器说:" + reply);
		socket.close();
	}
	public static void main(String[] args) throws IOException {
		UDPClient clint = new UDPClient();
		clint.createDatagramSocket();
	}
}

服务端实现的事例代码:

public class UDPserver {
	public void createUDPserverScoket() throws IOException {
		/*
		 * 接收客户端发送的数据
		 */
		//1.创建服务器端的DatagramSocket ,指定端口,
		DatagramSocket socket = new DatagramSocket(8080);
		//2.创建数据报,用于接收客户端发送的数据
		byte[] data = new byte[1024];
		DatagramPacket packet = new DatagramPacket(data, data.length);
		//3.接收客户端发送过来的数据报
		System.out.println("***服务器已经启动,等带客户端***");
		socket.receive(packet);
		String info = new String(data, 0, packet.getLength());
		System.out.println("我是服务器,客户端说:" + info);
		
		/*
		 * 响应客户端数据
		 */
		//1.定义客户端的地址,端口,数据
		InetAddress address = packet.getAddress();
		int port = packet.getPort();
		byte[] data2 = "欢迎您!".getBytes();
		//2.创建数据报,包含响应的数据信息
		DatagramPacket packet2 = new DatagramPacket(data2, data2.length, address, port);
		//3.响应客户端
		socket.send(packet2);
		socket.close();
	}
	public static void main(String[] args) throws IOException {
		UDPserver server = new UDPserver();
		server.createUDPserverScoket();
	}
}

经验与技巧:

  • 对于同一个socket,如果关闭了输出流,则与该输出流关联的socket也会被关闭,所以一般不要关闭流,关闭socket即可
  • 多线程中,未设置优先级可能会导致运行时输出非常慢,可降低优先级
thread.setPriority(4)  //设置线程的优先级,范围为[1,10],默认为5 
  • 使用TCP通信传递对象
ObjetctOutputStream oos  = new  ObjectOutputStream(os);
User user = new User("admin", "1234");
oos.writeObject(user);
  • sockete编程传递文件

输入图片说明

转载于:https://my.oschina.net/u/3592080/blog/1305845

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值