第 8章网络功能北京大学计算机系代亚非
2第 8章网络功能
8.1 Java与 internet
8.2 使用 URL
8.3 访问 cgi
8.4 URL连接
8.5 Socket
8.6 internet应用
8.7 数据报
8.8 JDBC
8.9 小结
38.1 Java与网络
Java语言取得成功的领域之一就是网络
(其他语言 )数页代码 ---->(Java)一条语句
TCP/IP(传输控制协议 /网间协议 )是 internet的主要协议,定义了计算机和外设进行通信所使用的规则 (应用层,传输层,网络层,链路层 ).
大多数基于 internet的应用程序被看作 TCP/IP协议的上一层,如,ftp,http,smtp,pop3,telnet,
nntp等
IP地址,TCP/IP网络中的每台计算机都有唯一的地址 --IP地址,
在 Java中,有一个用来存储 internet地址的类叫
InetAddress.
48.1 Java与网络
例,获取本机的 IP地址
import java.net.*;
public class getLocalHostTest
{ public static void main()
{ InetAddress myIP=null;
try {myIP=InetAddress.getLocalHost();}
catch{UnknowHostException e){}
System.out.println(myIP);
}
}
创建 inetAddress类不用构造函数 (不用 new)
58.1 Java与网络下面的例子演示 java如何根据域名自动到 DNS
上查找 IP地址 (与 DNS服务器的连接减至一行 )
import java.net.*;
public class getIP
{ public static void main(String args[])
{ InetAddress pku=null;
try{ pku=
InetAddress.getByName(“www.pku.edu.cn”);
}catch(UnknowHostException e) {}
System.out.println(pku); }
}
68.1 Java与网络
Java提供的网络功能有三大类,URL,Socket,
Datagram.
URL是三大功能中最高级的一种,通过 URL
Java程序可以直接送出或读入网络上的数据,
Socket是传统网络程序最常用的方式,可以想象为两个不同的程序通过网络的通信信道,
Datagram是更低级的网络传输方式,它把数据的目的纪录在数据包中,然后直接放在网络上,
7
URL Java 程序
DataInputStream
8.2 使用 URL
8.2.3 通过 URL读取 WWW服务器上的数据
将 URL位置的数据转成一个数据流
URL url=new
(http://www.pku.edu.cn/index.html”
DataInputStream data=new
DataInputStream(url.openStream());
从数据流中读出数据
String line=data.readLine()
while( line! =null) line=data.readLine()
88.2 使用 URL
例,从给定的位置中读数据 (ReadURLData.prj)
http://www.pku.edu.cn/
connect
<html>
<head><title><...></title></head>
<body>
action
URL url
Button
Frame主类
str=a.getText()
b=url.openStream()
TextArea c
line_str=b.readLine()
c.appendText(line_str);
TextField a
URL url=new URL(str)
DataInputStream b
98.2 使用 URLpublic boolean action(Event evt,Object arg){ try{
String line;
String str=textfield.getText();
url=new URL(str);
data=new DataInputStream(url.openStream());
while((line=data.readLine())!=null){
textarea.appendText(line); }
data.close();
}catch(MalformedURLException me){
System.out.println("Error URL");
}catch(IOException ie){
System.out.println("Error IO");
}
return true;
}
10
欢迎来访,你是第 个来访者 !1 2 7
你是第 <img SRC=“/cgi-bin/perl/counter.cgi”>个来访者客户端
HTML
服务器端
CGI程序
num+
+
img
cgi程序名
8.3 访问 cgi
起始页上的计数器及 cgi程序 (script)
118.3 访问 cgi
<form action="/scripts/test/query.idc" method=get>
send reset
Your name
数据库服务器
Web服务器
cgi程序form
<form action="/scripts/test/query.idc" method=post>
128.3 访问 cgi
cgi(公共网关 )程序可以用任何一种变成语言来写,
cgi将 web与外部程序连接起来(数据库查询等)
cgi程序要放在指定的目录下 cgi-bin目录,
cgi通常以 GET或 POST接收数据,
138.3 访问 cgi
从小应用中运行 CGI程序 (GET)
Socket runcgi=new
Socket(“www.jamsa.com”,80);
OutputStream os=runcgi.getOutputStream();
PrintStream ps=new PringtStream(os);
ps.println(“GET/cgi-bin/testcgi? arg1=val1&
args2=val2&arg3=val3”);
http://<机器名 >/<cgi程序路径 >?<查询串 >
148.3 访问 cgi
get方法把数据作为命令行中的参数传递给此
cgi (适用于少量参数的情况 )
Java cgi程序通过 main方法的串参数接受命令行,
C cgi程序通过访问环境变量中的查询串
QUERY_STRING,来获得查询串中的信息,
例如在 C程序中,char *str;
str=getevn(QUERY_STRING);
158.3 访问 cgiimport java.io.*; import java.net.*;
public class test_cgi
{ public static void main(String[] args) throws Exception
{ URL url = new URL
("http://pact518.hit.edu.cn/~wangqb/CGI-
BIN/test_2.cgi?012345678");
URLConnection connection = url.openConnection();
}
}
#include "stdio.h”
main()
{ char *Query_String;
Query_String = getenv("QUERY_STRING");
/*treatment*/
}
168.3 访问 cgi
从小程序中运行 CGI程序 (post)
post方法通过标准输出向 cgi传送参数 (适合参数较多的情况 )
用 post方法要有数据输出流
Socket runcgi=new Socket(“www.jamsa.com”,80);
建立 socket连接
DataOutputStream ds=runcgi.getOutputStream();
建立输入流
ds.println(“POST/cgi-bin/guestbook.pl”);
运行 cgi程序
178.3 访问 cgi
通知发送的数据类型
ds.println(“Content-type:plain/text”);
通知发送的数据长度
String data=“Hello world”
ds.println(“Content-length”+data.length+”\n”);
发送数据
ds.println(data);
188.3 访问 cgi
cgi接收 post方法送来的数据,就像从标准输入读数据一样,
getchar();gets();(C语言的情况 )(要建立数据流 )
cgi返回数据时要指明数据类型等信息,
printf(“Content-type:text/plain\n\n”);
或 printf(“Content-type:text/html\n\n”);
或 printf(“Content-type:image/gif\n\n”);
cgi规定服务器与外部程序交换信息的协议,
198.3 访问 cgi
String count_srt
URL url=new
URL(“http://202.118.239.38/cgi-bin/count.cgi”);
DataInputStream data=new
DataInputStream(url.openStrean());
count_str=data.readLine();(此处读入的是 cgi程序的输出 )
g.drawstring(“You are the,+count_str+,visitor”);
返回结果
DataInputStream
客户端
java程序服务器端
cgi程序
URL连接
208.4 URL连接
URL双向通信 (URLConection)
URLConnection是一个一 http为中心的类
1,建立连接
URL url=new
URL(“http://www.yahoo.com/”);
URLConnection con=url.openConnection();
2,向服务器端送数据
PrintStream outStream=new
PrintStream(con.getOutputStream());
outStream.println(string_data);
218.4 URL连接
3,从服务器读数据
DataInputStream inStream=new
DataInputStream(con.getInputStream());
inStream.readLine();
从 URL中得到的输出流通常与一个 CGI程序结合一起工作客户端
java程序
DataOutputStream
DataInputStream
CGI程序STDIN
STDOUT
服务器
( 排序
sort.cgi)
connectiuon getchar()putchar()
228.4 URL连接
URLConnection同时支持 get和 post两种机制一般的格式,
缺省情况下位 post method方式
URL和 URLConnection的区别在于前者代表一个资源的位置,后者代表一种连接
下面的例子中 Java程序访问 cgi程序,并传给它
10个数据,cgi程序胡接收后,排序,并传送回来,
连接的建立、数据流的建立,java如何发数据、
如何接收数据,cgi程序如何发送和接收
238.4 URL连接
import java.io.*; import java.net.*;
public class test_cgi
{public static void main(String[] args) throws Exception
{ URL url = new
URL("http://pact518.hit.edu.cn/~wangqb/cgi-bin/test.cgi");
URLConnection connection = url.openConnection();
connection.setDoOutput(true);
PrintStream out = new
PrintStream(connection.getOutputStream());
out.println("0123456789");
out.close();
248.4 URL连接
DataInputStream in = new
DataInputStream(connection.getInputStream());
String inputLine;
while ((inputLine = in.readLine()) != null)
System.out.println(inputLine);
System.in,read ();
in.close();
258.4 URL连接#include "stdio.h"
main()
{ int array[10]; int i,j,k;
printf("Content-type:text/plain\n\n");
for(i=0;i<=9;i++)
array[i]=getchar(); //read data from InputStream
for(i=0;i<=8;i++)
{ for(j=i;j<=9;j++)
{ if(array[i]<array[j])
{ k=array[j]; array[j]=array[i]; array[i]=k; }
}
}
printf("\nOutput number!\n");
for(i=0;i<=9;i++)
{ printf("%c",array[i]); } //write data to OutputStream
}
268.5 Socket
8.3.1 什么是 socket?
Socket是网络上运行的程序之间双向通信链路的最后终结点 网络服务
Mail
ftp
finger
20
telnet
数据结构
I/O缓冲区端口
21
23客户程序
Socket
IP,port
IP与端口的组合得出一个套接字,可以完全分辨
internet上运行的程序
27
internet服务 端口号 端口号internet服务
telnet 23 nntp 119
ftp 21 www 80
DNS 53 POP3 110
8.5 Socket
端口号,TCP/IP协议为每种服务定义了一个端口,当一台计算机上运行不同服务器程序时,,根据端口号不同提供相应的服务,
端口号不是计算机上的物理连接器,它只是具有软件意义的假想端口
288.5 Socket
在服务器端通过指定一个用来等待的连接的端口号创建一个 ServerSocket实例,
在客户端通过规定一个主机和端口号创建一个
socket实例,连到服务器上,
ServerSocket类的 accept方法使服务器处于阻塞状态,等待用户请求
Socket类和 ServerSocket是基于 TCP协议的,TCP协议提供 64个端口,256以内位保留端口,
298.5 Socket
在本地机器上测试网络程序用回送地址 Socket
socket=new Socket(“127.0.0.1”,2525);
如果网络的一端已经关闭,另一端读到 null.
建立 socket连接后,还应该建立输入输出数据流,
308.5 Socket
Server
ServerSocket(port #)
Server Socket.accept()
Socket()
OutputStream
InputStream
Close Socket
Client
Socket(host,port #)
Attempt the connection
OutputStream
InputStream
Close Socket
318.5 Socket
下面的例子演示一个简单的服务器与客户的交互,即服务器等待,客户访问,相互通一次信息,
328.5 Socket,8.5 Socket
创建服务器 (端口号 )
定义数据成员服务器等待网络连接建立 socket流读客户 端信息向用户发出一个字符串创建 Socket实例定义数据成员建立 socket流读 socket流
(接收并显示 )
送用户名给服务器关闭流
waiting for user
1111
connetcting client...
提示用户登录成功读 socket流User,java
338.5 Socket? 例,显示服务器与客户机间的通信 (服务器端 )
PrintStream ps=null;
DataInputStream dis=null;
String username;
ServerSocket serverSocket=null;
Socket clientSocket=null;
try { serverSocket=new
ServerSocket(1111);
}catch (IOException e)
{ System.out.println(,Error”+e);
System.exit(1);}
try { clientSocket=serverSocket.accept();
}catch (IOException e){
System.out.println("Accept failed.");System.exit(1);}
创建服务器 (端口号 )
定义数据成员服务器等待网络连接
348.5 Socket
,
ps=new PrintStream(clientSocket.getOutputStream());
dis=new
DataInputStream(clientSocket.getInputStream());
创建服务器 (端口号 )
定义数据成员服务器等待网络连接 建立 socket流 向客户发出登录要求
ps.println("login:"); ps.flush();
358.5 Socket
ps.println("login sucessful"); ps.flush();
System.out.println(username+" has logged off");}
读客户 端信息创建服务器 (端口号 )定义数据成员 服务器等待网络连接建立 socket流向用户发出登录要求通知客户连接完毕
if ((username=dis.readLine())==null)
{ System.out.println("readLine returned null");
System.exit(1); }
System.out.println("Username:"+username);
368.5 Socket
例,显示服务器与客户机间的通信 (客户端 )
创建 Socket实例
PrintStream output;
DataInputStream input;
String string;
Socket socket=null;
定义数据成员
try{socket=new Socket("127.0.0.1",1111);
}catch(IOException e){
System.out.println("Error,+e); return;}
input=new DataInputStream(socket.getInputStream());
output=new PrintStream(socket.getOutputStream());
建立 socket流
37,8.5 Socket
,
System.out.println(input.readLine());
创建 Socket实例定义数据成员建立 socket流读 socket流
(看到提示 )
System.in.read(bArray);
String s=new String(bArray,0);
output.println(s);
从键盘上读送用户名送给服务器端关闭流
socket.close();
input.close();
output.close();
System.out.println("Done");
System.out.println(input.readLine());
System.out.print("Logging off...");
读服务器反馈
38,8.5 Socket,8.5 Socket
创建服务器 (端口号 )
定义数据成员服务器等待网络连接建立 socket流读客户 端信息向用户发送字符串创建 Socket实例定义数据成员建立 socket流读 socket流
(看到提示 )
送用户名给服务器关闭流
waiting for user
1111
connetcting client...
提示用户登录成功读 socket流User,java
398.5 Socket
支持多客户
一种解决方案,
一台计算机上一次启动多个服务器程序,只要端口号不同,\myjava\clientAndServerTest
myserver <-------->myclient----f8.bat
myserver2<-------->myclient2----f9.bat
Server1(1111)
client(2222)Server2(2222)
client(1111)
Computer 1
408.5 Socket
第二种方案,
(支持多客户 )
Server
client1
client2
serverthreadserverthread
将服务器写成多线程的,不同的线程为不同的客户服务,
main()只负责循环等待线程负责网络连接,接收客户输入的信息
418.5 Socket
,
客户 1
客户 2
服务器线程 ()
线程 2
线程 ( )
线程 ( )
42,8.5 Socket
创建服务器 (端口号 )
定义数据成员服务器等待网络连接建立 socket流读客户 端信息提示用户输入客户名创建 Socket实例定义数据成员建立 socket流读 socket流
(看到提示 )
送用户名给服务器关闭流
waiting for user
1111
connetcting client...
提示用户登录成功读 socket流User,java
438.5 Socketpublic static void main(String args[])
{ServerSocket serverSocket=null;
try{serverSocket=new ServerSocket(1111);
}catch(Exception e){
System.out.println(”Error”+e);System.exit(1);}
while(true)
{Socket clientSocket=null;
System.out.println("waiting for users...");
try { clientSocket=serverSocket.accept();
}catch(IOException e){
System.out.println("accept failed:"+e);}
new serverThread(clientSocket).start();
}}
448.5 Socketclass serverThread extends Thread{ DataInputStream input; PrintStream output;
String user; Socket clientSocket;
serverThread(Socket clientSocket)
{ this.clientSocket=clientSocket; }
public void run()
{ try{ input=new DataInputStream
(clientSocket.getInputStream());
output=System.out; user=input.readLine();
System.out.println(user+" Connected!");
}catch(IOException e){ }
try {while(true) { String string;
if((string=input.readLine())==null) break;
output.println(user+string); output.flush(); }
}catch(Exception e){ return; }
System.out.println(user+ "has disconnected.");
try{ clientSocket.close(); input.close();
}catch(Exception e){ return; } }}
45
server
Hello 1076Hello 1071
abc
WAIT GO…abcWAIT GO…def
def
8.5 Socket
例,通过服务器交换信息 (exchangebyserver)
468.5 Socket
,
服务器
(1111)
accept
socket
客户
IP client1
线程客户
IP client2
线程服务器一端为了能接收多个客户的信息,它的输入流,输出流都是数组型的,
ServerSocket.accept()等待用户连接,一旦连接上,
则调用服务程序,
服务程序的主要内容是网络的读写,多客户的原因,网络读写的功能用多线程实现,因此将此部分功能单独分离出来,构成线程类
478.5 Socket
client1
client2
serviceRequest
serverServerSocket Socket
getOutputStream
getInputStream
reader.run reader.run
服务器端
accept()
reader.start()
read_net_input
write_net_output()
48
client()
write.run
write_net_output()
read_net_input()
close_server()
客户端
writer.start()
paint()
socket
getLocalPort()
getInputStream
getOutputStream
服务器
8.5 Socket
498.7 Datagram
TCP/IP传输层由两个并列的协议,TCP,UDP.
一般套接字 (TCP)提供一个可靠的传输模型作为两个网络端点的字节流,有纠错能力,
UDP没有保持的连接和数据流,数据报是一个网络上发送的独立信息,它的到达,到达时间,以及内容不能得到保证,
socket
server client
datagram
server client
508.7 Datagram
TCP提供高可靠性服务,适用于一次要传输交换大量报文的情况,信道上传递的包不需要源地址和目的地址
UDP提供高效率服务,适用于依次传输交换少量报文的情形 (如数据库查询 ),每个数据包要包含目的地址和端口号,
数据报文的使用以包为中心,打包,拆包,
Java.net包支持两种不同的在网络上送数据的方法,一般套接字和数据报文套接字,
518.7 Datagram
发出报文的标准步骤如下,
1,定义数据成员
DatagramSocket socket;
DatagramPacket packet;
InetAddress address;(用来存放接收方的地址 )
int port; ;(用来存放接收方的端口号 )
2,创建数据报文 Socket对象
try {socket=new DatagramSocket(1111);}
catch(java.net.SocketException e) {}
socket 绑定到一个本地的可用端口,等待接收客户的请求,
528.7 Datagram
3.分配并填写数据缓冲区 (一个字节类型的数组 )
byte[] Buf=new byte[256];
存放从客户端接收的请求信息,
4.创建一个 DatagramPacket
packet=new DatagramPacket(buf,256);
用来从 socket接收数据,它只有两个参数
5,服务器阻塞
socket.receive(packet);
在客户的请求报道来之前一直等待
538.7 Datagram
6,从到来的包中得到地址和端口号
InetAddress address=packet.getAddress();
int port=packet.getPort();
7,将数据送入缓冲区
或来自文件,或键盘输入
8,建立报文包,用来从 socket上发送信息
packet=new DatagramPacket
(buf,buf.length,address,port);
9,发送数据包 10.关闭 socket
socket.send(packet); socket.close();
548.7 Datagram
客户端接收包的步骤如下,
1,定义数据成员
int port; InetAddress address;
DatagramSocket socket;
DatagramPacket packet;
byte[] sendBuf=new byte[256];
2,建立 socket
socket=new DatagramSocket();
558.7 Datagram
3,向服务器发出请求报文
address=InetAddress.getByName(args[0]);
port=parseInt(args[1]);
packet=new
DatagramPacket(sendBuf,256,address,port);
socket.send(packet);
这个包本身带有客户端的信息
4,客户机等待应答
packet=new DatagramPacket(sendBuf,256);
socket.receive(packet);(如果没有到就一直等待,因此实用程序要设置时间限度 )
568.7 Datagram
5,处理接收到的数据
String received=new String(packet.getData(),0);
System.out.println(received);
数据报套接字首先是强调发送方和接收方的区别,同时也指出服务器和客户之间的不同,
一个客户机必须事先知道服务器的地址和端口,
以便进行出事连接
一个服务器从它接收到的数据报文中读取客户端的地址和端口,
578.7 Datagram
,建立数据报 socket();
建立一个报文包 packet
等待请求报文建立数据报 socket
建立一个请求包发出请求获得对方地址构成信息包发送出去创建接收包等待接收
588.8 小结
实现网络功能要靠 URL类,URLConection类,
Socket类和 DatagramSocket类
网络上的数据传送是将网络连接转换成输入输出流
DataInputStream和 DataOutputStream
(PrintStream)是网间流的载体,
URL适用于 web应用,如访问 http服务器是高层服务
URLConection的另一边通常是 cgi程序
cgi程序完成客户端与外部程序的交互
598.6 小结
向 cgi传送数据有 get和 post两种方法
cgi通过访问环境变量或读标准输入获得数据
回绕地址可用于在本地机器上调试网络程序
Socket适用于面向连接的,可靠性要求高的应用
Datagram适用于效率要求高的应用
Socket是由 IP和端口构成的一种网上通信链路的一端
Socket通信要分别运行服务器和客户程序
服务器程序是多线程的,可处理多个客户的请求
60作业
编写一个会话程序
要求,
会话双方可以自由通话,看到对方发来,bye”则退出