Java 基础知识九(网络编程)
UDP
DatagramSocket:通讯的数据管道
-send 和receive方法
-(可选,多网卡)绑定一个IP和Port
DatagramPacket
-集装箱:封装数据
-地址标签:目的地IP+Port
package org.example.net;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class UdpRecv {
public static void main(String[] args) throws Exception {
DatagramSocket ds = new DatagramSocket(3000);
byte[] buf = new byte[1024];
DatagramPacket dp = new DatagramPacket(buf, 1024);
System.out.println("UdpRecv:我在等待信息");
ds.receive(dp);
System.out.println("UdpRecv:我接收到信息");
String strRecv = new String(dp.getData(), 0, dp.getLength()) + " from " + dp.getAddress().getHostAddress() + ":" + dp.getPort();
System.out.println(strRecv);
Thread.sleep(1000);
System.out.println("UdpRecv:我要发送信息");
String str = "hello world 222";
DatagramPacket dp2 = new DatagramPacket(str.getBytes(), str.length(), InetAddress.getByName("127.0.0.1"), dp.getPort());
ds.send(dp2);
System.out.println("UdpRecv:我发送信息结束");
ds.close();
}
}
package org.example.net;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class UdpSend {
public static void main(String[] args) throws Exception {
DatagramSocket ds = new DatagramSocket();
String str = "hello world";
DatagramPacket dp = new DatagramPacket(str.getBytes(), str.length(), InetAddress.getByName("127.0.0.1"), 3000);
System.out.println("UdpSend:我要发送信息");
ds.send(dp);
System.out.println("UdpSend:我发送信息结束");
Thread.sleep(1000);
byte[] buf = new byte[1024];
DatagramPacket dp2 = new DatagramPacket(buf, 1024);
System.out.println("UdpSend:我在等待信息");
ds.receive(dp2);
System.out.println("UdpSend:我接收到信息");
String str2 = new String(dp2.getData(), 0, dp2.getLength()) + " from " + dp2.getAddress().getHostAddress() + ":" + dp2.getPort();
System.out.println(str2);
ds.close();
}
}
TCP
TCP协议:有链接、保证可靠的无误差通讯
-1)服务器:创建一个ServerSocket,等待连接
-2)客户机:创建一个Socket,连接到服务器-
3)服务器:ServerSocket接收到连接,创建一个Socket和客户的Socket建立专线连接,后续服务器和客户机的对话(这一对Sock会在一个单独的线程(服务器端)上运行
4)服务器的ServerSocket继续等待连接,返回1
ServerSocket: 服务器码头
需要绑定port
如果有多块网卡,需要绑定一个IP地址
Socket: 运输通道
-客户端需要绑定服务器的地址和Port
-客户端往Socket输入流写入数据,送到服务端-客户端从Socket输出流取服务器端过来的数据
-服务端反之亦然
服务端等待响应时,处于阻塞状态
服务端可以同时响应多个客户端
服务端每接受一个客户端,就启动一个独立的线程与之对应
客户端或者服务端都可以选择关闭这对Socket的通道
实例
-服务端先启动,且一直保留
-客户端后启动,可以先退出
package org.example.net;
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
public class TcpClient {
public static void main(String[] args) {
try {
Socket s = new Socket(InetAddress.getByName("127.0.0.1"),8001);//需要服务端先开启
//同一个通道,服务端的输出流就是客户端的输入流;服务端的输入流就是客户端的输出流
// 开启通道的输入流
InputStream ips =s.getInputStream();
BufferedReader brNet = new BufferedReader(new InputStreamReader(ips));
OutputStream ops = s.getOutputStream();//开启通道的输出流
DataOutputStream dos = new DataOutputStream(ops);
BufferedReader brKey = new BufferedReader(new InputStreamReader(System.in));
while (true) {
String strWord = brKey.readLine();
if (strWord.equalsIgnoreCase("quit")) {
break;
}else{
System.out.println("I want to send:" + strWord);
dos.writeBytes(strWord + System.getProperty("line.separator") );
System.out.println("Server said :" + brNet.readLine());
}
}
}catch (IOException e){
e.printStackTrace();
}
}
}
package org.example.net;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class TcpServer {
public static void main(String[] args) {
try {
ServerSocket ss = new ServerSocket(8001);//驻守在8001端口
Socket s = ss.accept();//阻寒,等到有客户端连接上来
System.out.println("welcome to the java world");
InputStream ips = s.getInputStream();//有人连上来,打开输入流
OutputStream ops = s.getOutputStream();//打开输出流
// 同一个通道,服务端的输出流就是客户端的输入流;服务端的输入流就是客户端的输出流
ops.write("Hello,client!".getBytes()); //输出一句话给客户端
BufferedReader br = new BufferedReader(new InputStreamReader(ips));
//从客户端读取一句话
System.out.println("client said:" + br.readLine());
ips.close();
ops.close();
s.close();
ss.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
server2 处理多客户端
package org.example.net;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class TcpServer2 {
public static void main(String[] args) {
try {
ServerSocket ss = new ServerSocket(8001);//驻守在8001端口
while (true){
Socket s = ss.accept();//阻寒,等到有客户端连接上来
System.out.println("a new client coming");
new Thread(new Worker(s)).start();
}
}catch (IOException e){
e.printStackTrace();
}
}
}
package org.example.net;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class Worker implements Runnable {
Socket s;
public Worker(Socket s) {
this.s = s;
}
@Override
public void run() {
try {
System.out.println("server has started");
InputStream ips = s.getInputStream();//有人连上来,打开输入流
OutputStream ops = s.getOutputStream();//打开输出流
BufferedReader br = new BufferedReader(new InputStreamReader(ips));
DataOutputStream dos = new DataOutputStream(ops);
while (true) {
String strWord = br.readLine();
System.out.println("client said:" + strWord + ":" + strWord.length());
if (strWord.equalsIgnoreCase("quit")) {
break;
}
String strEcho = strWord + " echo";
// dos.writeBytes(strWord + System.getProperty("line.separator"));
System.out.println("Server said :" + strWord + "---->" + strEcho);
dos.writeBytes(strWord + "---->" + strEcho + System.getProperty("line.separator"));
}
br.close();
//关闭包装类,会自动关闭包装类中所包装过的底层类。所以不用调用ips.close()
dos.close();
s.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
HTTP
Java HTTP编程(java.net包)
-支持模拟成浏览器的方式去访问网页
-URL,Uniform Resource Locator,代表一个资源http://www.ecnu.edu.cn/index.html?a=1&b=2&c=3
-URLConnection
获取资源的连接器
根据URL的openConnection(方法获得URLConnection
connect方法,建立和资源的联系通道
getInputStream方法,获取资源的内容
package org.example.net;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.util.List;
import java.util.Map;
public class URLConnectionGetTest {
public static void main(String[] args) {
try {
String urlName = "https://www.baidu.com";
URL url = new URL(urlName);
URLConnection connection = url.openConnection();
connection.connect();
//打印http的头部信息
Map<String, List<String>> headers = connection.getHeaderFields();
for (Map.Entry<String, List<String>> entry : headers.entrySet()) {
String key = entry.getKey();
for (String value : entry.getValue()) {
System.out.println(key + ":" + value);
}
}
//输出将要收到的内容属性信息
System.out.println("-----------------------");
System.out.println("getcontentType:"+connection.getContentType());
System.out.println("getcontentLength:"+ connection.getContentLength());
System.out.println("getcontentEncoding:?"+ connection.getContentEncoding());
System.out.println("getDate:"+ connection.getDate());
System.out.println("getExpiration:"+ connection.getExpiration());
System.out.println("getLastModifed:"+ connection.getLastModified());
System.out.println("----------");
BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream(),"UTF-8"));
//输出收到的内容
String line ="";
while ((line= br.readLine())!= null){
System.out.println(line);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
package org.example.net;
import java.io.*;
import java.net.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
public class URLConnectionPostTest {
public static void main(String[] args) throws IOException {
String urlstring = "https://tools.usps.com/go/zipLookupAction.action";
Object userAgent = "HTTPie/0.9.2";
Object redirects = "1";
CookieHandler.setDefault(new CookieManager(null, CookiePolicy.ACCEPT_ALL));
Map<String, String> params = new HashMap<String, String>();
params.put("tAddress", "1 Market street");
params.put("tcity", "San Francisco");
params.put("sstate", "CA");
String result = doPost(new URL(urlstring), params,
userAgent == null ? null : userAgent.toString(),
redirects == null ? -1 : Integer.parseInt(redirects.toString()));
System.out.println(result);
}
public static String doPost(URL url, Map<String, String> nameValuePairs, String userAgent, int redirects) throws IOException {
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
if (userAgent != null)
connection.setRequestProperty("User-Agent", userAgent);
if (redirects >= 0)
connection.setInstanceFollowRedirects(false);
connection.setDoOutput(true);
//输出请求的参数
try (PrintWriter out = new PrintWriter(connection.getOutputStream())) {
boolean first = true;
for (Map.Entry<String, String> pair : nameValuePairs.entrySet()) {
//参数必须这样拼接a = 1 & b = 2 & c = 3
if (first) {
first = false;
} else {
out.print('&');
}
String name = pair.getKey();
String value = pair.getValue();
out.print(name);
out.print('=');
out.print(URLEncoder.encode(value, "UTF-8"));
}
}
String encoding = connection.getContentEncoding();
if (encoding == null)
{
encoding = "UTF-8";
}
if (redirects > 0) {
int responseCode = connection.getResponseCode();
System.out.println("responsecode:" + responseCode);
if (responseCode == HttpURLConnection.HTTP_MOVED_PERM
|| responseCode == HttpURLConnection.HTTP_MOVED_TEMP
|| responseCode == HttpURLConnection.HTTP_SEE_OTHER) {
String location = connection.getHeaderField("Location");
if (location != null) {
URL base = connection.getURL();
connection.disconnect();
return doPost(new URL(base, location), nameValuePairs, userAgent, redirects - 1);
}
}
} else if (redirects == 0) {
throw new IOException("Too many redirects");
}
StringBuilder response = new StringBuilder();
try (Scanner in = new Scanner(connection.getInputStream(),encoding))
{
while(in.hasNextLine()){
response.append(in.nextLine());
response.append("\n");
}
} catch (IOException e) {
InputStream err = connection.getErrorStream();
if (err == null) throw e;
try (Scanner in = new Scanner(err)) {
response.append(in.nextLine());
response.append("\n");
}
}
return response.toString();
}
}
HTTPClient
java.net.http包
取代URLConnection 支持HTTP/1.1和HTTP/2 实现大部分HTTP方法主要类
-HttpClient -HttpRequest- HttpResponse
package org.example.net;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class JDKHttpClientGetTest {
public static void main(String[] args) throws IOException, InterruptedException {
doGet();
}
public static void doGet() {
try {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder(URI.create("http://www.baidu.com")).build();
HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
} catch (Exception e) {
e.printStackTrace();
}
}
}
Httpcomponents
hc.apache.org,Apache出品从HttpClient进化而来,是一个集成的Java HTIP工具包
-实现所有HTTP方法:get/post/put/delete
-支持自动转向
-支持https协议
-支持代理服务器等
NIO
·Buffer 缓冲区,一个可以读写的内存区域-ByteBuffer, CharBuffer, DoubleBuffer, IntBuffer, LongBufferShortBuffer (StringBuffer 不是Buffer缓冲区)
四个主要属性
capacity 容量,position 读写位置
limit 界限,mark标记,用于重复一个读/写操作
Channel 通道
全双工的,支持读/写(而Stream流是单向的)
-支持异步读写
-和Buffer配合,提高效率
-ServerSocketChannel 服务器TCP Socket 接入通道,接收客户端-SocketChannel TCP Socket通道,可支持阻寒/非阻塞通讯-DatagramChannel UDp 通道
-FileChannel 文件通道
elector多路选择器
-每隔一段时间,不断轮询注册在其上的Channel-如果有一个Channel有接入、读、写操作,就会被轮询出来进行后续IO操作
-根据SelectionKey可以获取相应的Channel,
-避免过多的线程
-SelectionKey四种类型
·OP_CONNECT
·OP_ACCEPT
·OP READ
·OP WRITE
package org.example.NIO;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
import java.util.UUID;
public class NioClient {
public static void main(String[] args) {
String host = "127.0.0.1";
int port = 8001;
Selector selector = null;
SocketChannel socketchannel = null;
try {
selector = Selector.open();
socketchannel = SocketChannel.open();
socketchannel.configureBlocking(false);//非阻塞
//如果直接连接成功,则注册到多路复用器上,发送请求消息,读应答
if (socketchannel.connect(new InetSocketAddress(host, port))) {
socketchannel.register(selector, SelectionKey.OP_READ);
doWrite(socketchannel);
} else {
socketchannel.register(selector, SelectionKey.OP_CONNECT);
}
} catch (IOException e) {
e.printStackTrace();
}
while (true) {
try {
selector.select(1000);
Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator<SelectionKey> it = selectedKeys.iterator();
SelectionKey key = null;
while (it.hasNext()) {
key = it.next();
it.remove();
try {
handleInput(selector, key);
} catch (Exception e) {
if (key != null) {
key.cancel();
if (key.channel() != null)
key.channel().close();
}
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
public static void doWrite(SocketChannel sc)throws IOException {
byte[] str = UUID.randomUUID().toString().getBytes();
ByteBuffer writeBuffer = ByteBuffer.allocate(str.length);
writeBuffer.put(str);
writeBuffer.flip();
sc.write(writeBuffer);
}
public static void handleInput(Selector selector, SelectionKey key) throws IOException, InterruptedException {
if(key.isValid()) {//判断是否连接成功
SocketChannel sc = (SocketChannel) key.channel();
if (key.isConnectable()) {
if (sc.finishConnect()) {
sc.register(selector, SelectionKey.OP_READ);
}
}
if (key.isReadable()) {
ByteBuffer readBuffer = ByteBuffer.allocate(1024);
int readBytes = sc.read(readBuffer);
if (readBytes > 0) {
readBuffer.flip();
byte[] bytes = new byte[readBuffer.remaining()];
readBuffer.get(bytes);
String body = new String(bytes, "UTF-8");
System.out.println("server said :" + body);
} else if (readBytes < 0) {
//对端链路关闭
key.cancel();
sc.close();
} else
; // 读到字节,忽略
}
Thread.sleep(5000);
doWrite(sc);
}
}
}
package org.example.NIO;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
public class NioServer {
public static void main(String[] args) throws IOException {
int port = 8001;
Selector selector = null;
ServerSocketChannel servChannel = null;
try {
selector = selector.open();
servChannel = ServerSocketChannel.open();
servChannel.configureBlocking(false);
servChannel.socket().bind(new InetSocketAddress(port), 1024);
servChannel.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("服务器在8001端口守候");
} catch (IOException e) {
e.printStackTrace();
System.exit(1);
}
while (true) {
try {
selector.select(1000);
Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator<SelectionKey> it = selectedKeys.iterator();
SelectionKey key = null;
while (it.hasNext()) {
key = it.next();
it.remove();
try {
handleInput(selector, key);
} catch (Exception e) {
if (key != null) {
key.cancel();
if (key.channel() != null)
key.channel().close();
}
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
try {
Thread.sleep(500);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
public static void handleInput(Selector selector, SelectionKey key) throws IOException {
if (key.isValid()) {//判断是否连接成功
if (key.isAcceptable()) {
ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
SocketChannel sc = ssc.accept();
sc.configureBlocking(false);
sc.register(selector, SelectionKey.OP_READ);
}
if (key.isReadable()) {
SocketChannel sc = (SocketChannel) key.channel();
ByteBuffer readBuffer = ByteBuffer.allocate(1024);
int readBytes = sc.read(readBuffer);
if (readBytes > 0) {
readBuffer.flip();
byte[] bytes = new byte[readBuffer.remaining()];
readBuffer.get(bytes);
String request = new String(bytes, "UTF-8");
System.out.println("server said :" + request);
String response = request + " 666";
doWrite(sc,response);
} else if (readBytes < 0) {
//对端链路关闭
key.cancel();
sc.close();
} else
; // 读到字节,忽略
}
}
}
public static void doWrite(SocketChannel channel,String response) throws IOException {
if (response != null && response.trim().length() > 0) {
byte[] bytes = response.getBytes();
ByteBuffer writeBuffer = ByteBuffer.allocate(bytes.length);
writeBuffer.put(bytes);
writeBuffer.flip();
channel.write(writeBuffer);
}
}
}
AIO
package org.example.Aio;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.util.UUID;
public class AioClient {
public static void main(String[] a){
try {
AsynchronousSocketChannel channel = AsynchronousSocketChannel.open();
channel.connect(new InetSocketAddress("localhost", 8001), null, new CompletionHandler<Void, Void>() {
public void completed(Void result, Void attachment){
String str = UUID.randomUUID().toString();
channel.write(ByteBuffer.wrap(str.getBytes()), null, new CompletionHandler<Integer, Object>() {
@Override
public void completed(Integer result, Object attachment){
try {
System.out.println("write " +str + " , and wait response");
ByteBuffer buffer = ByteBuffer.allocate(1024);
channel.read(buffer, buffer, new CompletionHandler<Integer, ByteBuffer>() {
@Override
public void completed(Integer result_num, ByteBuffer attachment) {
attachment.flip();
CharBuffer charBuffer = CharBuffer.allocate(1024);
CharsetDecoder decoder = Charset.defaultCharset().newDecoder();
decoder.decode(attachment, charBuffer, false);
charBuffer.flip();
String data = new String(charBuffer.array(), 0, charBuffer.limit());
System.out.println("server said: " + data);
try {
channel.close();
}catch (Exception e){
e.printStackTrace();
}
}
@Override
public void failed(Throwable exc, ByteBuffer attachment) {
System.out.println("read error "+ exc.getMessage());
}
});
channel.close();
}catch (Exception e){
e.printStackTrace();
}
}
public void failed(Throwable exc, Object attachment){
System.out.println("write error ");
}
});
}
public void failed(Throwable exc, Void attachment){
System.out.println("faild ");
}
});
Thread.sleep(10000);
}catch (Exception e){
e.printStackTrace();
}
}
}
package org.example.Aio;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.AsynchronousByteChannel;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
public class AioServer {
public static void main(String[] args) throws IOException {
AsynchronousServerSocketChannel server = AsynchronousServerSocketChannel.open();
server.bind(new InetSocketAddress("localhost", 8001));
System.out.println(" server is witing at port 8001");
server.accept(null, new CompletionHandler<AsynchronousSocketChannel, Object>() {
@Override
public void completed(AsynchronousSocketChannel channel, Object attchment){
server.accept(null, this);
ByteBuffer buffer = ByteBuffer.allocate(1024);
channel.read(buffer, buffer, new CompletionHandler<Integer, ByteBuffer>() {
@Override
public void completed(Integer result_num, ByteBuffer attachment) {
attachment.flip();
CharBuffer charBuffer = CharBuffer.allocate(1024);
CharsetDecoder decoder = Charset.defaultCharset().newDecoder();
decoder.decode(attachment, charBuffer, false);
charBuffer.flip();
String data = new String(charBuffer.array(),0,charBuffer.limit());
System.out.println("client said: "+data);
channel.write(ByteBuffer.wrap((data + " 666").getBytes()));
try {
channel.close();
}catch (Exception e){
e.printStackTrace();
}
};
@Override
public void failed(Throwable exc, ByteBuffer attachment) {
System.out.println("read error "+ exc.getMessage());
}
});
}
public void failed(Throwable exc, Object attachment){
System.out.println("failed "+ exc.getMessage());
}
});
while (true){
try {
Thread.sleep(5000);
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
}