-------android培訓、java培訓、java學習型技術博客、期待與您交流! ----------
知識點三 網絡編程應用
一、TCP併發執行請求
一)圖片上傳:
第一、客戶端:
1、創建服務端點
2、讀取客戶端以後圖片數據
3、通過Socket輸出流將數據發給服務端
4、讀取服務端反饋信息
5、關閉客戶端
第二、服務端
對於客戶端併發上傳圖片,服務端如果單純的使用while(true)循環式有侷限性的,當A客戶端連接上以後,被服務端獲取到,服務端執行具體的流程,這時B客戶端連接就只有等待了,因爲服務端還未處理完A客戶端的請求,還有循環來回執行下須accept方法,所以暫時獲取不到B客戶端對象,那麼爲了可讓多個客戶端同時併發訪問服務端,那麼服務端最好就是將每個客戶端封裝到一個單獨的線程,這樣就可以同時處理多個客戶端的請求。如何定義線程呢?只要明確每個客戶端要在服務端執行的代碼即可,將改代碼存入到run方法中。
示例一:
/*
需求:上傳圖片。
*/
/*
客戶端。
1,服務端點。
2,讀取客戶端已有的圖片數據。
3,通過socket 輸出流將數據發給服務端。
4,讀取服務端反饋信息。
5,關閉。
*/
import java.io.*;
import java.net.*;
class PicClient
{
public static void main(String[] args)throws Exception
{
Socket s = new Socket("192.168.1.254",10007);
FileInputStream fis = new FileInputStream("c:\\1.bmp");
OutputStream out = s.getOutputStream();
byte[] buf = new byte[1024];
int len = 0;
while((len=fis.read(buf))!=-1)
{
out.write(buf,0,len);
}
//告訴服務端數據已寫完
s.shutdownOutput();
InputStream in = s.getInputStream();
byte[] bufIn = new byte[1024];
int num = in.read(bufIn);
System.out.println(new String(bufIn,0,num));
fis.close();
s.close();
}
}
/*
服務端
*/
class PicServer
{
public static void main(String[] args) throws Exception
{
ServerSocket ss = new ServerSocket(10007);
Socket s = ss.accept();
InputStream in = s.getInputStream();
FileOutputStream fos = new FileOutputStream("server.bmp");
byte[] buf = new byte[1024];
int len = 0;
while((len=in.read(buf))!=-1)
{
fos.write(buf,0,len);
}
OutputStream out = s.getOutputStream();
out.write("上傳成功".getBytes());
fos.close();
s.close();
ss.close();
}
}
示例二:
/*
需求:上傳圖片。
*/
/*
客戶端。
1,服務端點。
2,讀取客戶端已有的圖片數據。
3,通過socket 輸出流將數據發給服務端。
4,讀取服務端反饋信息。
5,關閉。
*/
import java.io.*;
import java.net.*;
class PicClient
{
public static void main(String[] args)throws Exception
{
if(args.length!=1)
{
System.out.println("請選擇一個jpg格式的圖片");
return ;
}
File file = new File(args[0]);
if(!(file.exists() && file.isFile()))
{
System.out.println("該文件有問題,要麼補存在,要麼不是文件");
return ;
}
if(!file.getName().endsWith(".jpg"))
{
System.out.println("圖片格式錯誤,請重新選擇");
return ;
}
if(file.length()>1024*1024*5)
{
System.out.println("文件過大,沒安好心");
return ;
}
Socket s = new Socket("192.168.1.254",10007);
FileInputStream fis = new FileInputStream(file);
OutputStream out = s.getOutputStream();
byte[] buf = new byte[1024];
int len = 0;
while((len=fis.read(buf))!=-1)
{
out.write(buf,0,len);
}
//告訴服務端數據已寫完
s.shutdownOutput();
InputStream in = s.getInputStream();
byte[] bufIn = new byte[1024];
int num = in.read(bufIn);
System.out.println(new String(bufIn,0,num));
fis.close();
s.close();
}
}
/*
服務端
這個服務端有個侷限性。當A客戶端連接上以後。被服務端獲取到。服務端執行具體流程。
這時B客戶端連接,只有等待。
因爲服務端還沒有處理完A客戶端的請求,還有循環回來執行下次accept方法。所以
暫時獲取不到B客戶端對象。
那麼爲了可以讓多個客戶端同時併發訪問服務端。
那麼服務端最好就是將每個客戶端封裝到一個單獨的線程中,這樣,就可以同時處理多個客戶端請求。
如何定義線程呢?
只要明確了每一個客戶端要在服務端執行的代碼即可。將該代碼存入run方法中。
*/
class PicThread implements Runnable
{
private Socket s;
PicThread(Socket s)
{
this.s = s;
}
public void run()
{
int count = 1;
String ip = s.getInetAddress().getHostAddress();
try
{
System.out.println(ip+"....connected");
InputStream in = s.getInputStream();
File dir = new File("d:\\pic");
File file = new File(dir,ip+"("+(count)+")"+".jpg");
while(file.exists())
file = new File(dir,ip+"("+(count++)+")"+".jpg");
FileOutputStream fos = new FileOutputStream(file);
byte[] buf = new byte[1024];
int len = 0;
while((len=in.read(buf))!=-1)
{
fos.write(buf,0,len);
}
OutputStream out = s.getOutputStream();
out.write("上傳成功".getBytes());
fos.close();
s.close();
}
catch (Exception e)
{
throw new RuntimeException(ip+"上傳失敗");
}
}
}
class PicServer
{
public static void main(String[] args) throws Exception
{
ServerSocket ss = new ServerSocket(10007);
while(true)
{
Socket s = ss.accept();
new Thread(new PicThread(s)).start();
}
//ss.close();
}
}
二)客戶端併發登陸:
客戶端通過鍵盤錄入用戶名。服務端對這個用戶名進行校驗。如果該用戶存在,在服務端顯示xxx,已登陸。並在客戶端顯示 xxx,歡迎光臨。如果該用戶存在,在服務端顯示xxx,嘗試登陸。並在客戶端顯示 xxx,該用戶不存在。最多就登錄三次。
/*
客戶端通過鍵盤錄入用戶名。
服務端對這個用戶名進行校驗。
如果該用戶存在,在服務端顯示xxx,已登陸。
並在客戶端顯示 xxx,歡迎光臨。
如果該用戶存在,在服務端顯示xxx,嘗試登陸。
並在客戶端顯示 xxx,該用戶不存在。
最多就登錄三次。
*/
import java.io.*;
import java.net.*;
class LoginClient
{
public static void main(String[] args) throws Exception
{
//建立Socket鏈接
Socket s = new Socket("192.168.1.254",10008);
//讀取鍵盤錄入
BufferedReader bufr =
new BufferedReader(new InputStreamReader(System.in));
PrintWriter out = new PrintWriter(s.getOutputStream(),true);
BufferedReader bufIn =
new BufferedReader(new InputStreamReader(s.getInputStream()));
for(int x=0; x<3; x++)
{
String line = bufr.readLine();
if(line==null)
break;
out.println(line);
String info = bufIn.readLine();
System.out.println("info:"+info);
if(info.contains("歡迎"))
break;
}
bufr.close();
s.close();
}
}
//客戶端分配線程的代碼,封裝客戶端線程的形式就是如此(Tomcat底層原理其中之一)
class UserThread implements Runnable
{
private Socket s;
UserThread(Socket s)
{
this.s = s;
}
public void run()
{
//獲得客戶端的ip地址
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip+"....connected");
try
{
for(int x=0; x<3; x++)
{
BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));
String name = bufIn.readLine();
if(name==null)
break;
BufferedReader bufr = new BufferedReader(new FileReader("user.txt"));
PrintWriter out = new PrintWriter(s.getOutputStream(),true);
String line = null;
boolean flag = false;
while((line=bufr.readLine())!=null)
{
if(line.equals(name))
{
flag = true;
break;
}
}
if(flag)
{
System.out.println(name+",已登錄");
out.println(name+",歡迎光臨");
break;
}
else
{
System.out.println(name+",嘗試登錄");
out.println(name+",用戶名不存在");
}
}
s.close();
}
catch (Exception e)
{
throw new RuntimeException(ip+"校驗失敗");
}
}
}
class LoginServer
{
public static void main(String[] args) throws Exception
{
ServerSocket ss = new ServerSocket(10008);
while(true)
{
Socket s = ss.accept();
new Thread(new UserThread(s)).start();
}
}
}
三)瀏覽器客戶端-自定義服務端
客戶端:瀏覽器 (telnet)
服務端:自定義
import java.net.*;
import java.io.*;
class ServerDemo
{
public static void main(String[] args) throws Exception
{
ServerSocket ss = new ServerSocket(11000);
Socket s = ss.accept();
System.out.println(s.getInetAddress().getHostAddress());
InputStream in = s.getInputStream();
byte[] buf = new byte[1024];
int len = in.read(buf);
System.out.println(new String(buf,0,len));
PrintWriter out = new PrintWriter(s.getOutputStream(),true);
out.println("<font color='red' size='7'>客戶端你好</font>");
s.close();
ss.close();
}
}
四)瀏覽器客戶端-Tomcat服務端
客戶端:瀏覽器客戶端。
服務端:Tomcat服務器。
五)自定義瀏覽器-Tomcat服務端
客戶端:自定義瀏覽器。
服務端:Tomcat服務器。
示例:
import java.io.*;
import java.net.*;
/*
自己定義的客戶端
*/
class MyIE
{
public static void main(String[] args)throws Exception
{
Socket s = new Socket("127.0.0.1",8080);
PrintWriter out = new PrintWriter(s.getOutputStream(),true);
out.println("GET /myweb/demo.html HTTP/1.1");
//*/*表示所有的都支持
out.println("Accept: */*");
out.println("Accept-Language: zh-cn");
out.println("Host: 127.0.0.1:11000");
out.println("Connection: closed");
//一定要寫空行,和請求體分開
out.println();
out.println();
BufferedReader bufr = new BufferedReader(new InputStreamReader(s.getInputStream()));
String line = null;
while((line=bufr.readLine())!=null)
{
System.out.println(line);
}
s.close();
}
}
六)自定義圖形界面瀏覽器-Tomcat服務端
客戶端:自定義圖形界面瀏覽器。
服務端:Tomcat服務器。
示例一:
/*
瀏覽器是應用層的軟件,而我們的Socket走的是傳輸層,傳輸層的協議帶有應用層的消息頭
所以顯示的信息比較多
*/
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
class MyIEByGUI
{
private Frame f;
private TextField tf;
private Button but;
private TextArea ta;
private Dialog d;
private Label lab;
private Button okBut;
MyIEByGUI()
{
init();
}
public void init()
{
f = new Frame("my window");
f.setBounds(300,100,600,500);
f.setLayout(new FlowLayout());
tf = new TextField(60);
but = new Button("轉到");
ta = new TextArea(25,70);
d = new Dialog(f,"提示信息-self",true);
d.setBounds(400,200,240,150);
d.setLayout(new FlowLayout());
lab = new Label();
okBut = new Button("確定");
d.add(lab);
d.add(okBut);
f.add(tf);
f.add(but);
f.add(ta);
myEvent();
f.setVisible(true);
}
private void myEvent()
{
okBut.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
d.setVisible(false);
}
});
d.addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent e)
{
d.setVisible(false);
}
});
tf.addKeyListener(new KeyAdapter()
{
public void keyPressed(KeyEvent e)
{
try
{
if(e.getKeyCode()==KeyEvent.VK_ENTER)
showDir();
}
catch (Exception ex)
{
}
}
});
but.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
try
{
showDir();
}
catch (Exception ex)
{
}
}
});
f.addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent e)
{
System.exit(0);
}
});
}
private void showDir()throws Exception
{
//清空控制檯
ta.setText("");
String url = tf.getText();//http://192.168.1.254:8080/myweb/demo.html
int index1 = url.indexOf("//")+2;
int index2 = url.indexOf("/",index1);
String str = url.substring(index1,index2);
String[] arr = str.split(":");
String host = arr[0];
int port = Integer.parseInt(arr[1]);
String path = url.substring(index2);
//ta.setText(str+"...."+path);
Socket s = new Socket(host,port);
PrintWriter out = new PrintWriter(s.getOutputStream(),true);
out.println("GET "+path+" HTTP/1.1");
out.println("Accept: */*");
out.println("Accept-Language: zh-cn");
out.println("Host: 127.0.0.1:11000");
out.println("Connection: closed");
out.println();
out.println();
BufferedReader bufr = new BufferedReader(new InputStreamReader(s.getInputStream()));
String line = null;
while((line=bufr.readLine())!=null)
{
//在控制檯打印出來
ta.append(line+"\r\n");
}
s.close();
}
public static void main(String[] args)
{
new MyIEByGUI();
}
}
示例二(改進後的代碼):
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
class MyIEByGUI2
{
private Frame f;
private TextField tf;
private Button but;
private TextArea ta;
private Dialog d;
private Label lab;
private Button okBut;
MyIEByGUI2()
{
init();
}
public void init()
{
f = new Frame("my window");
f.setBounds(300,100,600,500);
f.setLayout(new FlowLayout());
tf = new TextField(60);
but = new Button("轉到");
ta = new TextArea(25,70);
d = new Dialog(f,"提示信息-self",true);
d.setBounds(400,200,240,150);
d.setLayout(new FlowLayout());
lab = new Label();
okBut = new Button("確定");
d.add(lab);
d.add(okBut);
f.add(tf);
f.add(but);
f.add(ta);
myEvent();
f.setVisible(true);
}
private void myEvent()
{
okBut.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
d.setVisible(false);
}
});
d.addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent e)
{
d.setVisible(false);
}
});
tf.addKeyListener(new KeyAdapter()
{
public void keyPressed(KeyEvent e)
{
try
{
if(e.getKeyCode()==KeyEvent.VK_ENTER)
showDir();
}
catch (Exception ex)
{
}
}
});
but.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
try
{
showDir();
}
catch (Exception ex)
{
}
}
});
f.addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent e)
{
System.exit(0);
}
});
}
private void showDir()throws Exception
{
ta.setText("");
String urlPath = tf.getText();//http://192.168.1.254:8080/myweb/demo.html
URL url = new URL(urlPath);
URLConnection conn = url.openConnection();
InputStream in = conn.getInputStream();
byte[] buf = new byte[1024];
int len = in.read(buf);
ta.setText(new String(buf,0,len));
}
public static void main(String[] args)
{
new MyIEByGUI2();
}
}
三、URL和URLConnection
一)URL:
URI:範圍更大,條形碼也包含於此範圍
URL:範圍較小,即域名
1、方法:
1)構造函數:URL(String protocol,String host,int port,String file)
---> 依protocol,host,port,file創建URL對象
2)String getProtocol() ---> 獲取協議
3)String getHost() ---> 獲取主機名
4)int getPort() ---> 獲取端口號
5)String getFile() ---> 獲取URL文件名
6)String getPath() ---> 獲取此URL的路徑部分
7)String getQuery() ----> 獲取此URL的查詢部,客戶端傳輸的特定信息
2、一般輸入網址,是不帶端口號的,此時可進行設置,在URL中寫port,若port爲-1,則分配一個默認的80端口,否則用自己定義的,如
int port = getPort();
if(port == -1)
port = 80;
二)URLConnection:
1、方法:
1)URLConnection openConnection() ---> 表示到URL所引用的遠程對象的鏈接
2)InputStream getInputStream():獲取輸入流
3)OutputStream getOutputStream():獲取輸出流
示例一(URL):
import java.net.*;
class URLDemo
{
public static void main(String[] args) throws MalformedURLException
{
URL url = new URL("http://192.168.1.254/myweb/demo.html?name=haha&age=30");
//獲取協議
System.out.println("getProtocol() :"+url.getProtocol());
//獲取主機
System.out.println("getHost() :"+url.getHost());
//獲取端口
System.out.println("getPort() :"+url.getPort());
//獲取路徑
System.out.println("getPath() :"+url.getPath());
// 獲取此 URL 的文件名。
System.out.println("getFile() :"+url.getFile());
//獲取此 URL 的查詢部
System.out.println("getQuery() :"+url.getQuery());
/*
url默認不寫的時候,返回的是-1,因爲要先要對url進行解析,解析不到的端口就定義爲-1
int port = getPort();
if(port==-1)
port = 80;
getPort()==-1
*/
}
}
/*
String getFile()
獲取此 URL 的文件名。
String getHost()
獲取此 URL 的主機名(如果適用)。
String getPath()
獲取此 URL 的路徑部分。
int getPort()
獲取此 URL 的端口號。
String getProtocol()
獲取此 URL 的協議名稱。
String getQuery()
獲取此 URL 的查詢部
*/
示例二(URLConnection):
/*
3G也會用的上URLConnection
*/
import java.net.*;
import java.io.*;
class URLConnectionDemo
{
public static void main(String[] args) throws Exception
{
URL url = new URL("http://192.168.1.254:8080/myweb/demo.html");
URLConnection conn = url.openConnection();
System.out.println(conn);
InputStream in = conn.getInputStream();
byte[] buf = new byte[1024];
int len = in.read(buf);
System.out.println(new String(buf,0,len));
}
}
示例三(改進版的MyIEByGUI):
import java.awt.*;
import java.awt.event.*;
import java.net.*;
import java.io.*;
class MyIEGUI
{
//創建全局變量
private Frame f;
private Button but;
private TextField tf;
private TextArea ta;
private Dialog d;
private Label lab;
private Button okBut;
//構造函數,初始化窗體
MyIEGUI()
{
init();
}
//創建窗體和組件,並將事件添加進來
public void init()
{
//設置窗體
f = new Frame("my window");
f.setBounds(300,200,600,500);
f.setLayout(new FlowLayout());
//創建組件
but = new Button("轉到");
tf = new TextField(60);
ta = new TextArea(25,75);
d = new Dialog(f,"提示信息-self",true);
d.setBounds(300,100,300,150);
d.setLayout(new FlowLayout());
lab = new Label();
okBut = new Button("確定");
//將組件添加到窗體
f.add(tf);
f.add(but);
f.add(ta);
d.add(lab);
d.add(okBut);
//添加事件
myEvent();
//設置窗體可見
f.setVisible(true);
}
//常見引發的時間
private void myEvent()
{
//給but添加一個活動監聽器
but.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
try{
showInfo();
}catch (Exception ex){
throw new RuntimeException("客戶端登陸失敗");
}
}});
okBut.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
d.setVisible(false);
}
});
//給文本框添加鍵盤事件
tf.addKeyListener(new KeyAdapter()
{
public void keyPressed(KeyEvent e)
{
try{
if(e.getKeyCode()==KeyEvent.VK_ENTER)
showInfo();
}catch (Exception ex){
throw new RuntimeException("客戶端登陸失敗");
}
}
});
//關閉窗體事件
f.addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent e)
{
System.exit(0);
}
});
d.addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent e)
{
d.setVisible(false);
}
});
}
private void showInfo()throws Exception
{
ta.setText("");
//獲取路徑
String urlPath = tf.getText();//http://192.168.1.101:8080/myweb/myIE.html
//創建URL對象,解析路徑
URL url = new URL(urlPath);
//獲取連接
URLConnection conn = url.openConnection();
//獲取輸入流,讀取獲得的數據,並顯示在文本框中
InputStream in = conn.getInputStream();
byte[] buf = new byte[1024];
int len=in.read();
ta.setText(new String(buf,0,len));
}
public static void main(String[] args)
{
new MyIEGUI();
}
}
知識點四 幾個小知識點
1、InetAddress對象封裝的是 IP地址
InetSocketAddress對象封裝的是 IP+端口, InetSocketAddress是SocketAddress的子類。
2、ServerSocket對象中的構造函數:
ServerSocket(int port,int backlog),其中的backlog表示隊列的最大長度,即最多連入客戶端的個數,即最大連接數,可以自己設定。
3.域名解析:
即域名解析:DNS
在進行訪問的時候,會現在本地的hosts文件(C:\WINDOWS\system32\drivers\etc\hosts)中找對應的映射,若有,則直接返回請求,若無,則到公網的映射列表即DNS中找對應的映射,找到後,將主機名對應的IP地址返回給本機,本機通過這個IP地址找到對應的服務器。
host的兩點應用:
1.我們可以在host映射文件中自己配置自己的IP地址和域名的映射表。
2.可屏蔽一些惡意網址,即將對應的映射關係寫入hosts中,將IP地址改爲本機的迴環地址,那麼會直接找到hosts,就不會將請求發送出去
3.了一些殺毒軟件就運用了這個功能來屏蔽那些木馬或者是釣魚網站。
最新最全的的java學習視頻教程:http://pro.net.itcast.cn/View-22-1458.aspx
-------android培訓、java培訓、java學習型技術博客、期待與您交流! ----------
詳細請查看:http://edu.csdn.net/heima