- java網(wǎng)絡(luò)編程
- 阻塞IO
- NIO
1. java網(wǎng)絡(luò)編程
-
基礎(chǔ)知識(shí)
1.ip地址和端口號(hào)
2.tcp/udp協(xié)議
3.URL
4.InetAddress
public void test() throws IOException{
//使用URL讀取網(wǎng)頁(yè)
//創(chuàng)建一個(gè)URL實(shí)例
URL url=new URL("http://www.baidu.com");
//通過(guò)openstream方法虎丘資源字節(jié)輸入流
InputStream is=url.openStream();
//字節(jié)輸入轉(zhuǎn)為字符,不指定編碼,中文可能亂碼
InputStreamReader isr=new InputStreamReader(is,"UTF-8");
//字符輸入假如緩存,提高讀寫(xiě)效率
BufferedReader br=new BufferedReader(isr);
String data = br.readLine();
while (data != null) {
System.out.println(data);//輸出
data=br.readLine();
}
br.close();
isr.close();
is.close();
}
-
socket
1.創(chuàng)建socket實(shí)例
2.客戶端鏈接
3.服務(wù)端鏈接
4.總結(jié)
客戶端代碼
public void socket() throws IOException {
//1.創(chuàng)建客戶端socket,指定服務(wù)器地址和端口
Socket socket = new Socket("localhost", 10086);
//2.獲取輸出流
OutputStream os = socket.getOutputStream();
PrintWriter pw = new PrintWriter(os); //輸出包裝成打印流
pw.flush();
socket.shutdownOutput();
//3.獲取輸入流,讀取服務(wù)器響應(yīng)數(shù)據(jù)
InputStream is = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String info = null;
if ((info = br.readLine()) != null) {
System.out.println("我是客戶端,服務(wù)器端說(shuō)" + info);
}
//4.關(guān)閉資源
br.close();
is.close();
pw.close();
os.close();
socket.close();
}
服務(wù)端代碼
/**
* 基于TCP協(xié)議的socket通信,實(shí)現(xiàn)用戶登錄,服務(wù)端
*/
public void serverSocket() throws IOException{
//1.創(chuàng)建一個(gè)服務(wù)器端的socket,即ServerSocket,指定綁定端口,監(jiān)聽(tīng)端口
ServerSocket serverSocket=new ServerSocket(10086);
//2.調(diào)用accept 開(kāi)始監(jiān)聽(tīng),等待客戶端連接
Socket socket=serverSocket.accept();
//3.獲取輸入流,讀取客戶端
InputStream is = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String info = null;
if ((info = br.readLine()) != null) {
System.out.println("我是服務(wù)器,客戶端說(shuō)" + info);
}
socket.shutdownOutput();//關(guān)閉輸入流
//4.獲取輸出流,響應(yīng)客戶端信息
OutputStream os = socket.getOutputStream();
PrintWriter pw = new PrintWriter(os); //輸出包裝成打印流
pw.write("歡迎您......");
pw.flush();
//5.關(guān)閉資源
pw.close();
os.close();
br.close();
is.close();
socket.close();
serverSocket.close();
}
總結(jié)
-
創(chuàng)建ServerSocket和Socket
serverSocket.accept() -
打開(kāi)連接到Socket的輸入輸出流
socket.openInputStream() -
按照協(xié)議對(duì)Socket進(jìn)行讀寫(xiě)
包裝流輸入輸出 -
關(guān)閉輸入,輸出流,關(guān)閉socket
serverSocket還要關(guān)閉socket
2. 阻塞IO
java的I/O接口
-
基于字節(jié)
InputStream或OutputStream -
基于字符
Writer和Reader -
基于磁盤(pán)
File -
基于網(wǎng)絡(luò)
Socket
一直是阻塞的,會(huì)等到數(shù)據(jù)到來(lái)時(shí)才返回
eg:serverSocket.accept()一直等到有客戶端socket連接時(shí)啟用一個(gè)線程
總結(jié)
1.BIO數(shù)據(jù)在寫(xiě)入OutputStream或者從InputStream讀取時(shí)都有阻塞
2.當(dāng)前一些需要大量HTTP長(zhǎng)連接
NIO
基本原理
- 是事件到來(lái)時(shí),才執(zhí)行,不是像BIO那樣始終監(jiān)視
- 有線程間通信方式,通過(guò)wait/notify方法,保證每次上下文切換都是有意義的,提高CPU的效率
- 有一個(gè)線程處理所有的IO事件
通信模型
雙向通道
代碼
客戶端
public Selector mSelector;
public void initClient(String ip, int port) throws IOException {
//1.獲取一個(gè)Socket通道
SocketChannel channel = SocketChannel.open();
//2.設(shè)置通道為非阻塞
channel.configureBlocking(false);
//3.獲得一個(gè)通道管理器
mSelector = Selector.open();
//客戶端連接服務(wù)器,方法執(zhí)行并沒(méi)有實(shí)現(xiàn)連接,需要在listen方法中調(diào)用
//用channel.finisConnection 才能完成連接
channel.connect(new InetSocketAddress(ip, port));
//將通道管理器和通道綁定,并為該通道注冊(cè)selecionKey.OP_CONNECT事件
channel.register(mSelector, SelectionKey.OP_CONNECT);
}
/**
* 采用輪詢的方式監(jiān)聽(tīng)selector上是否有需要處理的事件,有則進(jìn)行處理
*/
public void listen() throws IOException {
//輪詢方式
while (true) {
mSelector.select();
//獲得selector中選中的迭代器
Iterator iterator = mSelector.selectedKeys().iterator();
while (iterator.hasNext()) {
SelectionKey key = (SelectionKey) iterator.next();
//刪除已選的key 防止重復(fù)
iterator.remove();
//連接事件發(fā)生
if (key.isConnectable()) {
SocketChannel channel= (SocketChannel) key.channel();
//如果正在連接,則完成連接
if (channel.isConnectionPending()) {
channel.finishConnect();
}
//設(shè)置成非阻塞
channel.configureBlocking(false);
//在這里可以給服務(wù)器發(fā)送消息
channel.write(ByteBuffer.wrap(
new String("向服務(wù)器發(fā)送數(shù)據(jù)").getBytes()));
//和服務(wù)端連接成功后,為了接收服務(wù)器消息,需要設(shè)置讀的權(quán)限
channel.register(mSelector,SelectionKey.OP_READ);
//
//獲得可讀事件
}else if(key.isReadable()){
read(key);
}
}
}
}
private void read(SelectionKey key) {
}
服務(wù)器端
//通道管理器
private Selector mSelector;
/**
* 獲得一個(gè)ServerSocket通道,并對(duì)改通道做一些初始化操作
*/
public void initServer(int port) throws IOException{
//獲得一個(gè)ServerSocket通道
ServerSocketChannel channel=ServerSocketChannel.open();
//2.設(shè)置通道為非阻塞
channel.configureBlocking(false);
//將通道對(duì)應(yīng)的serverSocket綁定到port端口
channel.socket().bind(new InetSocketAddress(port));
//3.獲得一個(gè)通道管理器
mSelector = Selector.open();
//將通道管理器和通道綁定,并為該通道注冊(cè)selecionKey.OP_ACCEPT事件
//注冊(cè)該時(shí)間后,當(dāng)事件到達(dá)時(shí),selector.select會(huì)反悔,
//如果該事件沒(méi)到達(dá)selector.select會(huì)一直阻塞
channel.register(mSelector, SelectionKey.OP_ACCEPT);
}
/**
* 采用輪詢的方式監(jiān)聽(tīng)selector上是否有需要處理的事件
*/
/**
* 采用輪詢的方式監(jiān)聽(tīng)selector上是否有需要處理的事件,有則進(jìn)行處理
*/
public void listen() throws IOException {
System.out.println("服務(wù)器端啟動(dòng)成功");
//輪詢方式
while (true) {
mSelector.select();
//獲得selector中選中的迭代器
Iterator iterator = mSelector.selectedKeys().iterator();
while (iterator.hasNext()) {
SelectionKey key = (SelectionKey) iterator.next();
//刪除已選的key 防止重復(fù)
iterator.remove();
//連接事件發(fā)生
if (key.isConnectable()) {
SocketChannel channel= (SocketChannel) key.channel();
//如果正在連接,則完成連接
if (channel.isConnectionPending()) {
channel.finishConnect();
}
//設(shè)置成非阻塞
channel.configureBlocking(false);
//在這里可以給服務(wù)器發(fā)送消息
channel.write(ByteBuffer.wrap(
new String("向服務(wù)器發(fā)送數(shù)據(jù)").getBytes()));
//和服務(wù)端連接成功后,為了接收服務(wù)器消息,需要設(shè)置讀的權(quán)限
channel.register(mSelector,SelectionKey.OP_READ);
//
//獲得可讀事件
}else if(key.isReadable()){
read(key);
}
}
}
}
private void read(SelectionKey key) {
}