常用基本类
InetAddress类是java中表示IP的类。主要用于Socket,ServerSocket,URL,DatagramSocket等
创建InetAddress用三个静态方法
getByName(String hostname)throws UnknownHostException
getAllByName(String hostname)
throws UnknownHostException
getLocalHost()
throws UnknownHostException
使用这三个静态方法创建InetAddress的时候,除了使用getByName中传递ip地址外(如果使用getByName传递一个ip会首先创建一个InetAddress不管是否存在,当显示的调用getHostName或者toString的时候才会进行网络连接),都会首先进行网络连接,会根据主机名去连接DNS服务器,来查找对应的主机名和ip,一定要捕获异常处理。
对于已经创建成功的InetAddress可以获取基本属性,getAddress()返回一个字节数组,可以利用
int unsigned=signByte<0?
signByte+256:
signByte转换为int。也可以利用它的长度来判断是IPv4或者IPv6。
两个InetAddress对象equals的条件是具有相同的IP,不管主机名是否相等
toString的表现形式为:hostname/ip
URL类,是一个final类,使用的是策略设计模式,协议就是策略。
构造URL的基本方法URL url=new URL("http://www.baidu.com"),如果创建未支持的协议的URL则会出现MalformedURLException异常。
URL主要由协议、授权机构、路径、片段标示符和查询字符串表示。
openStream():连接URL所指向的资源,执行客户端与服务器之间的握手,返回一个可读取的数据
openConnection():打开指定的URL的socket,返回一个URLConnection(表示一个打开网络资源的连接)
getContent()
在利用URL进行发送数据的时候,主要URL中只需出现ASCII中的固定子集,未出现的必须进行编码,利用URLEncoder来编码,要对每一部分编码,再用URLDecoder解析编码
URI类是纯粹的关于资源的标识和URI的解析,它没有网络获取功能,主要用于对于URL进行分析。
基于TCP的Socket编程(Socket和ServerSocket)
客户端Socket建立步骤:
1 利用构造函数创建一个新Socket
2 Socket尝试连接远程主机(在构造函数创建后,该socket就会自动连接远程主机)
3 一旦建立连接,此socket就会进行输入流和输出流操作。连接是全双工,双方可同时发送接受数据
4 当数据传输完毕后,一端就或两端就会关闭连接。HTTP1.0,要求每次请求得到服务器响应后就关闭连接。
创建Socket基本方法Socket socket=new Socket("www.ttt.com",80);一定要捕获异常,当主机名不存在的时候,抛出UnknownHostException异常,其他情况会抛出IOException,可以用来测试某一些端口是否可利用。
获取Socket的输入流,socket.getInputStream();可以通过这个来获取服务器返回的结果,在其调用read的时候会一直阻塞着。一般均要将其链接到过滤器流或者阅读器。
写入Socket的输出流,socket.getOutputStream();向服务器发送数据,但是这里务必要每次写入后加上out.write("\r\n\r\n"),out.flush(),关闭输出流。对于每行都要加上"\r\n"
判断一个socket当前是否打开,需要用如下方式:
isClose返回false仅在已经被关闭或者从未打开的时候
isConnected表示曾经打开过
boolean connected=socket.isConnected()&&! socket.isClosed();
SocketAddress类,主要用于存放暂时的Socket连接信息,将上次的连接保存后,下次直接利用connect来连接。创建一个SocketAddress,可以通过其子类InetSocketAddress来创建,
InetSocketAddress,此类实现 IP 套接字地址(IP 地址 + 端口号),
它还可以是一个对(主机名 + 端口号)。
InetSocketAddress(String hostname, int port)
;根据字符串指定的主机名来创建
ServerSocket建立步骤
1 使用ServerSocket()构造函数来在某个端口创建一个ServerSocket
2 ServerSocket使用其accept()监听此端口的所有入站请求。在没有请求的时候,该accept方法会一直阻塞,它会使得整个程序停止执行并且等待,直到有客户端尝试进行连接,此时就会返回一个连接客户端和服务器的Socket对象
3 调用输入输出流类型
4 关闭该Socket对象
5 继续等待
创建一个ServerSocket的基本方法ServerSocket server=new ServerSocket(1888);会抛出IOException和BindException的异常。
测试一个ServerSocket是否打开利用 ss.isBound()&& !ss.isClosed()来判断。
简单Socket和Server连接测试
客户端Socket
package com.client;
import java.io.IOException;
import java.io.*;
import java.net.Socket;
import java.net.UnknownHostException;
public
class FirstClient {
public
static
void main(String[] args) {
// TODO Auto-generated method stub
Socket client=
null;
try{
client=
new Socket(
"localhost",6666);
InputStream in=client.getInputStream();
OutputStream outs=client.getOutputStream();
BufferedOutputStream buffs=
new BufferedOutputStream(outs);
Writer out=
new OutputStreamWriter(buffs);
out.write(
"hello===");
//out.flush();
out.close();
//一定要关闭输出流,否则它会一直占用该端口以及资源
}
catch(UnknownHostException e)
{
e.printStackTrace();
}
catch(IOException e)
{
e.printStackTrace();
}
}
}
服务器端Socket
package com.server;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
public
class FirstServer {
public
static
void main(String[] args) {
// TODO Auto-generated method stub
try {
ServerSocket server =
new ServerSocket(6666);
while (
true) {
Socket client =
null;
try {
client = server.accept();
InputStream ins = client.getInputStream();
BufferedReader read =
new BufferedReader(
new InputStreamReader(ins));
String res = read.readLine();
read.close();
System.out.println(
"client request:" + res);
}
catch (IOException e) {
e.printStackTrace();
}
finally {
try {
if (client !=
null)
client.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
}
}
catch (IOException e) {
e.printStackTrace();
}
}
}
客户端服务器端发送和接受流
不管是客户端Socket处理流或者服务器端获得Socket处理流,不要随便关闭它们获得的输入流和输出流,因为关闭这些流的时候会将该Socket也给关闭了,这是由于流在关闭的时候会释放它所占有的资源,如句柄或端口。
输入流处理
输入流处理主要就是处理来自socket发送的请求信息,不管是客户端还是服务器端都需要先利用getInputstream获得一个socket传输的流。
下面是输入流中最关键的部分就是分析请求的头部,主要是在服务器端
Socket socket=
null;
BufferedReader netwin=
null;
//一般在网络中不用这种方式,仅仅一般测试用
try{
socket=
new Socket(
"localhost",2222);
String header=
"HTTP/1.0 200 OK\r\n"+
"Server:Apache 7.0\r\n"+
"Content-length:"+107+
"\r\n"+
"Content-type: text/html\r\n\r\n";
//输出流
OutputStream outfile=
new BufferedOutputStream(socket.getOutputStream());
Writer write=
new OutputStreamWriter(outfile);
//输入流
InputStream inputstream=socket.getInputStream();
BufferedInputStream in=
new BufferedInputStream(inputstream);
InputStreamReader inr=
new InputStreamReader(in);
//对于http请求的需要先判断是否是http协议
//判断请求是否是http协议主要就是处理输入流中的第一行
//第一种处理解析请求头部
StringBuffer request1=
new StringBuffer(100);
while(
true)
{
int c=in.read();
if(c=='\r' || c=='\n' || c==-1)
break;
request1.append((
char)c);
}
String requestHeader1=request1.toString();
if(requestHeader1.indexOf(
"HTTP/")!=-1)
write.write(header);
write.flush();
write.close();
//第二种处理解析请求头部
StringBuffer request2=
new StringBuffer(100);
while(
true)
{
int c=in.read();
if(c=='\r' || c=='\n' || c==-1)
break;
request2.append((
char)c);
}
//截取第一行每一部分
//一般http请求格式GET /index.html HTTP/1.0
String requestHeader2=request2.toString();
int firstSpace=requestHeader2.indexOf(' ');
int secondSpace=requestHeader2.indexOf(' ', firstSpace+1);
String fileName=requestHeader2.substring(firstSpace+1,secondSpace);
if(requestHeader1.indexOf(
"HTTP/")!=-1)
{
write.write(header);
write.flush();
write.close();
}
//第三种处理解析请求头部
StringBuffer request3=
new StringBuffer(100);
while(
true)
{
int c=in.read();
if(c=='\r' || c=='\n' || c==-1)
break;
request3.append((
char)c);
}
//截取第一行每一部分
//一般http请求格式GET /index.html HTTP/1.0
String requestHeader3=request3.toString();
//使用默认分隔符,包括空白字符,制表符,换行符,回车符,换页符
StringTokenizer st=
new StringTokenizer(requestHeader3);
String method=st.nextToken();
String version="";
String filename=st.nextToken();
String httpT="";
if(st.hasMoreTokens())
httpT=st.nextToken();
if(httpT.indexOf(
"HTTP/")!=-1)
{
write.write(header);
write.flush();
write.close();
}
}
catch(IOException e)
{
e.printStackTrace();
}
输出流处理
在利用http发送数据的时候,每一行都应该由\r\n结束,一般不要使用pringln这种,因为java在linux中换行是以\n结束,windows下换行是以\r\n。
但是在利用http进行请求与响应的过程中,两个都必须每次写入后最后要写入\r\n\r\n,再要将输出流flush以及关闭该输出流。如果不是用http请求一般只需要在每行加入\r\n
不管是客户端还是服务器端要发送流,就必须先getOutputStream来获取一个写入流,用于发送到另一端的Socket中。一般均要放到输出流或者书写器中。
输出流是以字节为单位写的,这样会加快数据的传输速度,便于传输。
书写器是以字符为单位写的,方便写入数据。
基本的输出流写入方式:
socket=
new Socket(
"localhost",2222);
OutputStream outs=socket.getOutputStream();
//利用缓冲来
BufferedOutputStream buffer=
new BufferedOutputStream(outs);
writer=
new OutputStreamWriter(buffer);
//在写入的过程中每一行必须要以\r\n结束
writer.write(
"hello");
//这里是一般请求则,只需要加上\r\n即可
writer.write(
"\r\n");
//当是http请求的时候需要这样处理,请求最后加上\r\n
//writer.write("GET /index.html http/1.0 ")
//writer.write("\r\n\r\n")
writer.flush();
writer.close();
当是对于http请求进行响应的时候就需要写入MIME首部,且返回文件的时候,该代码实例基本功能是传输客户端请求的页面,并且根据http协议传送首部,错误处理
//这里写入的只是一些小型文件的处理
InputStream in=
new FileInputStream(
"f:\\t.txt");
ByteArrayOutputStream out=
new ByteArrayOutputStream();
int b;
while((b=in.read())!=-1)out.write(b);
byte[] data=out.toByteArray();
//下面的是读取大文件处理的方式
// File file=new File("f:\\t.txt");
// DataInputStream fis=new DataInputStream(
// new BufferedInputStream(new FileInputStream(file)));
// //存放数据
// byte[] data=new byte[(int)file.length()];
// fis.readFully(data);//将文件读入到字节数组中
// fis.close();//直接在输出流中加入该data
//编写MIME首部的格式
String header=
"HTTP/1.0 200 OK\r\n"+
"Server:Apache 7.0\r\n"+
"Content-length:"+data.length+
"\r\n"+
"Content-type: text/html\r\n\r\n";
//开始写入输出流
socket=
new Socket(
"localhost",2222);
//利用缓冲来
OutputStream outfile=
new BufferedOutputStream(socket.getOutputStream());
Writer write=
new OutputStreamWriter(outfile);
//这里一般要先判断是否是http协议,
//if(request.indexof("HTTP")!=-1)
//write.write(header);
write.flush();
write.close();
//发送文件一般直接用输出流,不要用书写器
outfile.write(data);
outfile.flush();
outfile.close();
//当文件不存在的时候
//这里还是要判断是否是http协议,如果是先要添加MIME首部
write.write(
"HTTP/1.0 404 File Not Found\r\n");
write.write(
"Server:Apache 7.0\r\n");
write.write(
"Content-type:text/html");
write.write(
"\r\n\r\n");
//当不是http协议还要输出显示
write.write(
"<HTML>\r\n");
write.write(
"<HEAD><TITLE>File Not Found</TITLE></HEAD>\r\n");
write.write(
"<BODY>HTTP ERROR 404 :File Not Found\r\n");
write.write(
"</BODY></HTML>\r\n");
write.flush();
write.close();