java对网络的支持
1、java支持基于
流的通信(Stream-based communication),也支持
基于包的通信(backage-based communication)
2、
基于流的通信使用
TCP协议(传输控制协议),
基于包的通信使用
UDP协议(用户数据报协议);
3、相对于UDP协议,TCP协议能发现丢失的传输信息并且重新发送,
因此大多数java程序采用基于流的通信;
客户端/服务器数据交流
1、Java API提供用于创建套接字的类以用于程序的网络通信;
套接字(Socket)是两台主机之间的逻辑连接的端点,可以用来发送和接收数据;
2、示例代码:
<span style="color:#000000;">import java.net.*;
import java.io.*;、
class Server{
int port = 8000; //端口
try{
ServerSocket server = new ServerSocket(port); //创建服务器套接字
Socket socket = server.accept(); //创建套接字监听器
InputStream input = new InputStream(socket.getInputStream()); //创建服务器输入输出流
OutputStream output = new OutputStream(socket.getOutputStream());
//以下代码可以加入到一个while(true)块中,以实现客户端服务器之间不间断的数据交流
System.out.println(input.read()); //服务器从输入流中读取数据
output.write(aNumber); //服务器向输出流写入数据
}
catch(IOException e){ //由于输入输出流的存在,可能抛出IOException异常
System.err.println(e);
}
}
class Client{
int port = 8000; //端口
String host = "localHost"; //服务器主机名,localHost=127.0.0.1
try{
Socket socket = new Socket(host,port);
InputStream input = new InputStream(socket.getInputStream());
OutputStream output = new OutputStream(socket.getOutputStream());
System.out.println(input.read());
output.write(aNumber);
}
catch(IOException e){
System.err.println(e);
}
}</span>
※如果客户端服务器模型使用GUI构建的话,那么框架构建的代码要放在建立套接字连接的try/catch块之前,否知会引起线程阻塞,而无法显示GUI;
30.2 一个服务端对应多个客户端
1、单个服务端对应多个客户端:将各个客户端包装为线程,使用多线程交换数据流;
ServerSocket socket = new ServerSocket(port);
while(true){ //while(true)块能使服务端不停地获取新连接的客户端的套接字
Socket socket = serverSocket.accpet();
Thread thread = new ThreadClass(socket);
thread.start();
}
或者使用线程池(更方便对各个线程的客户端进行管理):
<span style="color:#000000;">ServerSocket server = new ServerSocket(port);
ExecutorService executor = Executors.newCachedPool();
while(true){ //while(true)块能使服务端不停地获取新连接的客户端的套接字
Socket socket = service.accept();
executor.execute(socket);
}</span>
2、示例代码:
<span style="color:#000000;">import java.io.*;
import java.net.*;
class Server{
int port = 8000;
try{
ServerSocket server = new ServerSocket(port);
while(true){
Socket socket = server.accept();
Thread thread = new ThreadClass(socket);
thread.start();
}
}
catch(IOException e){
System.err.println(e);
}
}
class ThreadClass{
private Socket socket ;
ThreadClass(socket){
this.socket = socket;
}
public void run(){
try{
InputStream input = new InputStream(socket.getInputStream());
OutputStream output = new OutPutStream(socket.getOutputStream());
System.out.println(input.read()); //服务器从输入流中读取数据
output.write(aNumber); //服务器向输出流写入数据
}
catch(IOException e){
System.err.println(e);
}
}
}</span>
※可以通过以下的方法对各个客户端的输入输出流进行控制(所有用户数据共享,通过限制线程数限制客户端数量等)
class JFrame{
List<Socket> list = new List<Socket>(); //记录所有客户端的套接字
static void main(){
new JFrame();
}
JFrame(){
//在try块之前,要完成主框架的构建,否则会陷入线程阻塞
try{
ExecutorService executor = Executors.newCachedPool();
while(true){ //while(true)块可以使服务器不停地获取新的客户端套接字
Socket socket = service.accept();
executor.execute(new Task(socket));
list.add(socket);
}
}
}
class Task() implements Runnable{
Socket socket;
Task(){ }
void run(){
try{
while(true){ //while(true)块使服务器客户端能持续地交换数据
InputStream in = new InputStream(socket.getInputStream());
input.read(); //从该个客户端读取数据流
for(Socket socket:list){
OutputStream out = new OutputSteam(socket.getOutputStream());
out.write(); //向每一个客户端写入数据流
}
}
}
catch(IOException)
}
}
}
30.3 InetAddress类:获取主机名、IP地址
1、从Socket套接字监听器类中获取
<span style="color:#000000;"> Socket socket = new Socket(host,port); //Socket socket = (new ServerSocket(port)).accept();
InetAddress inetAddress = socket.getInetAddress();
inetAddress.getHostName(); //获取主机名
inerAddress.getHostAddress(); //获取主机IP地址</span>
2、直接从主机名或IP地址构建
<span style="color:#000000;"> InetAddress inetAddress = InetAddress.getByName("hostName");
InetAddress inetAddress = InetAddress.getByName("HostIPAddress");</span>
30.4 applet 服务端
applet客户端:可以使用getCodeBase().getHost()以获取服务器的主机名,applet程序架设在服务端上面;
application:Socket socket = new Socket("localhost",8000);
applet:Socket socket = new Socket(getCodeBase().getHost(),8000);
30.5 发送和接收对象
可以在套接字Socket字流上使用
ObjectOutputStream和ObjectInputStream来发送和接收对象;
30.6 从Web服务器上读取文件
1、使用
URL的openStream方法对URL定位的文件加载到字流并读取;
2、模型:
void main(){
try{
URL url = new URL(urlString:String);
Scanner input = new Scanner(url.openStream());
while(input.hasNext()){
System.out.println(input.nextLine());
}
}
/*try{
URL url = new URL(urlString);
BufferedReader input = new BufferedReader(new InputStreamReader(url.openStream());
String str = "";
while((str=input.readLine()) != null){
System.out.println(str);
}
} //
catch(MalformedURLException e){ //URL格式错误抛出的异常
System.out.println(e.getMessage());
}
catch(IOException e){
System.out.println(e.getMessage());
}
finally{
input.close();
}
}
30.7 JEditorPane类
1、JEditorPane类:Swing中一个能自动加载显示普通文本、HTML文本、RTF文件的类
2、缺陷:含有Script代码的页面容易显示错乱 ,只能用于静态页面的读取;
3、模型
<span style="color:#000000;">void main(){
try{
if(urlStr.startsWith("http://")); //当URL地址以 http://开头时不做处理
//当URL以www.开头时,添加“http://”前缀
else if(urlStr.startsWith("www.")){
urlStr = "http://" + urlStr;
}
//当URL为本地文件时,将其包装为一个File类,再通过他获取绝对地址;
else{
File file = new File(urlStr);
urlStr = "file:" + file.getAbsolutePath();
}
URL url = new URL(urlString);
JEditorPane jep = new JEditorPane(url);
jep.setContentType("text/html;charset=utf-8"); //解决中文字符乱码的问题
jep.setPage(url); //在窗体上显示url定位的文件的文本内容
}catch(IOException ex){
}
}</span>