Socket -- 网络编程

网络编程的基础类

1.IP地址:
目前Java对IPv4和IPv6这两种IP地址进行了封装,实现类分别为Inet4Address和Inet6Address,它们都继承了类InetAddress。
InetAddress的实例对象包含以数字形式保存的IP地址,同时还可能包含主机名,提供了将主机名解析为IP地址和反向解析的方法。InetAddress对域名进行解析时使用本地机器配置或者DNS和网络信息服务来实现。对于DNS,本地需要向DNS服务器发送查询请求,然后服务器返回对应的IP地址,当然本地也会缓存一些主机名与IP地址的映射,提高性能。
InetAddress的构造方法不是公有的,只能通过提供的静态方法来获取InetAddress对象,最常用的是getByName(String host)方法,传入目标主机的名字,尝试连接DNS,获取对应的IP地址。还有一个getLocalHost()返回本地的IP地址。
2.输入输出流:
输出流是指向目的地写入的二进制序列,输入流是从数据源读取的二进制序列,都是以字节为单位的。
输出流的基类OutputStream:

  • write(byte[] b) :将字节数组中的所有字节写入输出流,等于write(b,0,b,length)。

  • flush() :将输出流缓存的所有字节写向它们的目标,只能保证正确进行输出,不能保证正确到达目标。

  • close() :关闭释放。

     **输入流的基类InputStream:**
    
  • read() :从输入流中读取数据的下一个字节,没有返回-1。

  • read(byte[] b) :从输入流中读取一定数量的字节,并存到缓冲区数组b中。

  • close() :关闭释放。

     **流的处理工具:**
     输出流:Java定义了一个抽象的基类java.io.Writer,对write方法进行了5次重载。最常用的子类是PrintWriter,因为具有强大的格式化输出能力,还有print()和println()方法可以高效的向输出流写入指定编码的对象。
     输入流:Java定义了一个抽象的基类java.io.Reader,最常用的子类InputStreamReader,是字节流通向字符流的桥梁,使用指定的字符集读取输入流中的数据并将其解码为字符,如new InputStreamReader(System.in)。
     通常还使用BufferedReader从字符输入流中读取文本,缓冲各个字符,实现高效读取,如:
     BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    

3.套接字:
套接字用于实现网络上的两个程序之间的连接与通信,连接的两端都分别有一个套接字。
流套接字: 用于面向连接,可靠的数据传输服务,实现无差错,无重复发送,并按顺序接收,用于TCP连接。如Socket,ServerSocket。
数据报套接字: 提供无连接服务,不保证数据传输的可靠性,有可能丢失或重复,用于UDP连接。如DatagramSocket。
原始套接字: 前两种为标准套接字,而原始套接字是可以读写内核没有处理的IP数据包,而标准套接字只能读取TCP或UDP的数据。如果要访问其他协议发送的数据,就必须使用原始套接字。

TCP编程

一对一通信:

package javaS.net.TCPsocket.one2one;

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 Server {
	public static void main(String[] args) throws IOException {
		//创建服务端套接字,提供监听端口,监听客户端是否发来请求
		ServerSocket server = new ServerSocket(888);
		//accep方法,使server服务端套接字一直处于阻塞状态,直到有客户端发来请求连接
		//创建一个socket实例接收客户端发来的请求,操作这个实例完成所需要的会话
		Socket socket = server.accept();
		
		//创建一个输入流来读取客户端发来的数据,这里使用缓冲输入流,实现高效读取
		InputStreamReader reader = new InputStreamReader(socket.getInputStream());
		BufferedReader buffer_reader = new BufferedReader(reader);
		//创建一个输出流,来放服务端的响应数据
		PrintWriter writer = new PrintWriter(socket.getOutputStream());
		
		//读出客户端的请求数据
		String request = buffer_reader.readLine();
		System.out.println("客服端的请求是:"+request);
		
		//把服务端的响应数据输入到输出流中
		String line = "你好,我是服务端!";
		writer.println(line);
		//因为输出流的内容可能并不是立即写回给客户端,所以这里显示刷新输出流
		writer.flush();
		
		//关闭IO流,Socket套接字
		writer.close();
		buffer_reader.close();
		socket.close();
		server.close();
	}
}

package javaS.net.TCPsocket.one2one;

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

//客户端
public class Client {
	public static void main(String[] args) throws IOException {
		//客户端只需要创建一个socket实例来实现会话需求即可,指定目标的IP地址和端口
		Socket socket = new Socket("127.0.0.1", 888);
		
		// 创建一个输入流来读取服务端发来的数据,这里使用缓冲输入流,实现高效读取
		InputStreamReader reader = new InputStreamReader(socket.getInputStream());
		BufferedReader buffer_reader = new BufferedReader(reader);
		// 创建一个输出流,来放客户端的请求数据
		PrintWriter writer = new PrintWriter(socket.getOutputStream());
		
		//把请求数据写入输出流,发送给服务端
		String readline = "你好,我是客户端!";
		writer.println(readline);
		writer.flush(); //显示刷新
		
		//从输入流中读取服务端返回来的数据
		String response = buffer_reader.readLine();
		System.out.println("服务端的响应是:"+response);
		
		//关闭IO流,Socket套接字
		writer.close();
		buffer_reader.close();
		socket.close();
	}
}

一对多通信:
服务端有两个类,一个实现runnable接口负责套接字以及流的处理,另一个负责监听连接和线程的分配。

package javaS.net.TCPsocket.one2more;

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

/*
 * 这个类实现了runnable接口,是一个线程类,负责套接字socket和IO流的处理。
 */
public class ServerSocketHandler implements Runnable{

	private Socket socket;
	//需要传入一个socket来处理
	public ServerSocketHandler(Socket socket) {
		this.socket = socket;
	}

	@Override
	public void run() {
		try {
			//创建一个输入流来读取客户端发来的数据,这里使用缓冲输入流,实现高效读取
			InputStreamReader reader = new InputStreamReader(socket.getInputStream());
			BufferedReader buffer_reader = new BufferedReader(reader);
			//创建一个输出流,来放服务端的响应数据
			PrintWriter writer = new PrintWriter(socket.getOutputStream());
			
			//从socket中读取出客服端的ip地址和端口,以及请求数据
			String client = "<"+socket.getInetAddress().toString()+" : "+socket.getPort()+">";
			String request = buffer_reader.readLine();
			System.out.println(client+" 说:"+request);
			
			//把服务端的响应数据写入输出流
			String line = client + "你好,我是服务端!";
			writer.println(line);
			writer.flush();
			
			//关闭io流和socket套接字
			writer.close();
			buffer_reader.close();
			socket.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
		
	}

}

package javaS.net.TCPsocket.one2more;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

/*
 * 这个服务端类实现线程池来进行线程分配,避忌频繁创建线程的开销。
 * 监听连接服务不变。
 */
public class ServerThreadPool {
	
	public static void main(String[] args) throws IOException {
		ServerSocket server = new ServerSocket(888);
		
		/*
		 * 使用高级线程池:
		 * 线程池大小根据负载情况自动调整
		 * 如果一个线程空闲60秒,移出线程池。
		 */
		Executor service = Executors.newCachedThreadPool();
		Socket socket = null;
		while(true) {
			socket = server.accept();
			service.execute(new ServerSocketHandler(socket));
		}
	}
}

客户端使用多个重复类,发起连接:

	package javaS.net.TCPsocket.one2more;

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

public class Client {
	public static void main(String[] args) throws IOException {
		//客户端只需要创建一个socket实例来实现会话需求即可,指定目标的IP地址和端口
		Socket socket = new Socket("127.0.0.1", 888);
		
		// 创建一个输入流来读取服务端发来的数据,这里使用缓冲输入流,实现高效读取
		InputStreamReader reader = new InputStreamReader(socket.getInputStream());
		BufferedReader buffer_reader = new BufferedReader(reader);
		// 创建一个输出流,来放客户端的请求数据
		PrintWriter writer = new PrintWriter(socket.getOutputStream());
		
		//把请求数据写入输出流,发送给服务端
		String readline = "你好,我是客户端!";
		writer.println(readline);
		writer.flush(); //显示刷新
		
		//从输入流中读取服务端返回来的数据
		String response = buffer_reader.readLine();
		System.out.println("服务端的响应是:"+response);
		
		//关闭IO流,Socket套接字
		writer.close();
		buffer_reader.close();
		socket.close();
	}
}

UDP编程

发送方:

package javaS.net.UDPsocket;

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

/*
 * 这是UDP网络编程的发送方
 */
public class Client {

	public static void main(String[] args) {
		
		try {
			//UDP使用DatagramSocket来发送和接收消息,没指定ip,默认本地,端口号随机
			//UDP是广播形式
			DatagramSocket sendSocket = new DatagramSocket();
			
			//编写发送消息,必须转为字节数组
			String msg = "你好,我是发送方!";
			byte[] buf = msg.getBytes();
			
			//发送方的IP地址和端口号
			int port = 8888;
			InetAddress ip = InetAddress.getLocalHost();
			//把数据,ip,端口封装在一个数据报DatagramPacket
			DatagramPacket sendPacket = new DatagramPacket(buf, buf.length, ip, port);
			//使用DatagramSocket发送数据报DatagramPacket
			sendSocket.send(sendPacket);
			
			//创建一个数据报和字节数组来接收返回的消息
			byte[] getBuf = new byte[1024];
			DatagramPacket getPacket = new DatagramPacket(getBuf,getBuf.length);
			sendSocket.receive(getPacket);
			//将字节数组转为字符串
			String backMsg = new String(getBuf,0,getPacket.getLength());
			System.out.println("接收方返回的消息是:"+backMsg);
			
			//关闭DatagramSocket
			sendSocket.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

接收方:

package javaS.net.UDPsocket;

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketAddress;

/*
 * 这是UDP网络编程的接收方
 */
public class Server {

	public static void main(String[] args) {
		try {
			//创建接收方的套接字,并指定可接收的ip地址和端口号,也可以使用SocketAddress来绑定监听的ip和端口
			InetAddress ip = InetAddress.getLocalHost();
			int port = 8888;
			DatagramSocket getSocket = new DatagramSocket(port, ip);
			
			//创建数据报和字节数组来接收发送方的消息
			byte[] buf = new byte[1024];
			DatagramPacket getPacket = new DatagramPacket(buf, buf.length);
			getSocket.receive(getPacket);
			//转为字符串输出
			String getMsg = new String(buf,0,getPacket.getLength());
			System.out.println("发送方发送的消息是:"+getMsg);
			//从数据报得到发送方的ip和端口
			InetAddress sendIP = getPacket.getAddress();
			int sendPort = getPacket.getPort();
			System.out.println("发送方的地址是:"+sendIP.getHostAddress()+" : "+sendPort);
			
			//从数据报得到发送方的套接字地址,里面就绑定了发送方的ip和端口
			SocketAddress sendAddress = getPacket.getSocketAddress();
			String feedback = "你好,我是接收方!";
			byte[] backBuf = feedback.getBytes();
			//把返回的消息封装到数据报中
			DatagramPacket sendPacket = new DatagramPacket(backBuf, backBuf.length,sendAddress);
			//返回给发送方
			getSocket.send(sendPacket);
			
			//关闭接收方的套接字
			getSocket.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

最后,参考学习链接

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
完整版:https://download.csdn.net/download/qq_27595745/89522468 【课程大纲】 1-1 什么是java 1-2 认识java语言 1-3 java平台的体系结构 1-4 java SE环境安装和配置 2-1 java程序简介 2-2 计算机中的程序 2-3 java程序 2-4 java类库组织结构和文档 2-5 java虚拟机简介 2-6 java的垃圾回收器 2-7 java上机练习 3-1 java语言基础入门 3-2 数据的分类 3-3 标识符、关键字和常量 3-4 运算符 3-5 表达式 3-6 顺序结构和选择结构 3-7 循环语句 3-8 跳转语句 3-9 MyEclipse工具介绍 3-10 java基础知识章节练习 4-1 一维数组 4-2 数组应用 4-3 多维数组 4-4 排序算法 4-5 增强for循环 4-6 数组和排序算法章节练习 5-0 抽象和封装 5-1 面向过程的设计思想 5-2 面向对象的设计思想 5-3 抽象 5-4 封装 5-5 属性 5-6 方法的定义 5-7 this关键字 5-8 javaBean 5-9 包 package 5-10 抽象和封装章节练习 6-0 继承和多态 6-1 继承 6-2 object类 6-3 多态 6-4 访问修饰符 6-5 static修饰符 6-6 final修饰符 6-7 abstract修饰符 6-8 接口 6-9 继承和多态 章节练习 7-1 面向对象的分析与设计简介 7-2 对象模型建立 7-3 类之间的关系 7-4 软件的可维护与复用设计原则 7-5 面向对象的设计与分析 章节练习 8-1 内部类与包装器 8-2 对象包装器 8-3 装箱和拆箱 8-4 练习题 9-1 常用类介绍 9-2 StringBuffer和String Builder类 9-3 Rintime类的使用 9-4 日期类简介 9-5 java程序国际化的实现 9-6 Random类和Math类 9-7 枚举 9-8 练习题 10-1 java异常处理 10-2 认识异常 10-3 使用try和catch捕获异常 10-4 使用throw和throws引发异常 10-5 finally关键字 10-6 getMessage和printStackTrace方法 10-7 异常分类 10-8 自定义异常类 10-9 练习题 11-1 Java集合框架和泛型机制 11-2 Collection接口 11-3 Set接口实现类 11-4 List接口实现类 11-5 Map接口 11-6 Collections类 11-7 泛型概述 11-8 练习题 12-1 多线程 12-2 线程的生命周期 12-3 线程的调度和优先级 12-4 线程的同步 12-5 集合类的同步问题 12-6 用Timer类调度任务 12-7 练习题 13-1 Java IO 13-2 Java IO原理 13-3 流类的结构 13-4 文件流 13-5 缓冲流 13-6 转换流 13-7 数据流 13-8 打印流 13-9 对象流 13-10 随机存取文件流 13-11 zip文件流 13-12 练习题 14-1 图形用户界面设计 14-2 事件处理机制 14-3 AWT常用组件 14-4 swing简介 14-5 可视化开发swing组件 14-6 声音的播放和处理 14-7 2D图形的绘制 14-8 练习题 15-1 反射 15-2 使用Java反射机制 15-3 反射与动态代理 15-4 练习题 16-1 Java标注 16-2 JDK内置的基本标注类型 16-3 自定义标注类型 16-4 对标注进行标注 16-5 利用反射获取标注信息 16-6 练习题 17-1 顶目实战1-单机版五子棋游戏 17-2 总体设计 17-3 代码实现 17-4 程序的运行与发布 17-5 手动生成可执行JAR文件 17-6 练习题 18-1 Java数据库编程 18-2 JDBC类和接口 18-3 JDBC操作SQL 18-4 JDBC基本示例 18-5 JDBC应用示例 18-6 练习题 19-1 。。。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值