一、Socket使用时应当注意的一些问题
1.设置超时,从套接字读取信息时,在有数据可供访问之前,读操作会被阻塞,如果此时主机不可达,那么程序将会等待很长时间,并因为系统操作系统的限制最终导致超时
调用
setSoTimeout方法设置
1  | Socket s = new Socket(...);  | 
对构造器
Socket(String host,int port),可以先构建一个无连接的套接字,再使用超时
1  | Socket s = new Socket();  | 
2.可中断套接字,用SocketChannel类
3.需要解析因特网地址时,可以用InetAddress类
4.为多个客户端服务时,可以用多线程解决
5.半关闭:套接字连接的一段UN可以终止其输出,同时仍可以接受来自另一端的数据,反过来也一样,调用Socket.shutdownInput或Socket.shutdownOutput
二、获取Web数
URI和URL
- URL是URI的一个特例,URI是个纯粹的语法结构,包含用来点位Web资源的字符串和各种组成功哪部分,URL包含了用于定位Web资源的足够信息,其他无法定位任何数据的URI,称之为URN
 - 一个URI具有一下语法:
[scema:]schemaSpecficPart[#fragment] 
i.包含schema:部分的URI成为绝对URI,否则为相对URI
ii.绝对URI的schemaSpecficPart不是以/揩油,则称为不透明的,如:mialto:pinnuli!hostname.com
iii.所有绝对的透明URI和所有相对URI都是分层的,如:http://hostname.com/index.html,../../java/net/Socket.html#Socket()
iv.一个分层URI的URI的schemaSpecficPart具有一下结构:[//authority][path][?query],基于服务器的URI,authority具有一下形式:[user-info@]host[:port]
- java中URI类的作用
- 解析表示福并将它分解成各种不同组成成分
 - 标识符的相对化和解析相对标识符
 
 
使用URLCollection
> URLConnection类可以比URL类有更多的控制
必须严格按照以下步骤进行操作:
1.调用URL类中的openConnection方法得到URLConnection对象:URLConnection connection = url.openConnection();
2.设置请求属性
3.调用connect方法连接远程资源:connection.connect();
4.建立连接后,可以查询头信息
5.访问资源数据,使用getInputStream方法获取一个输入流
这里的getInputStream/getOutputStream与Socket类的又很大的不同,这里具有很多处理请求和响应消息头时的强大功能
三、提交表单
1.提交数据之前,需要创建一个URLConnection对象1
2URL url = new URL("http;??host/script");
URLConnection connection = url.openConnection();
2.调用setDoOutput方法建立一个输出的连接1
2connection.setRequestMethod("POST");
connection.setDoOutput(true);
3.调用getOutputStream方法获得一个输出流,想服务器发送数据1
2
3OutputStreamWriter osw = new OutputStreamWriter(connection.getOutputStream(), "UTF-8");
osw.write(name1 + "=" + URLEncoder.eccode(value1,"UTF-8") + "&);
osw.write(name2 + "=" + URLEncoder.encode(value2,"UTF-8"));
4.关闭输出流1
2osw.flush();
osw.close();
5.调用getInputStream方法对服务器的响应1
2
3
4
5
6
7BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"));
StringBuffer response = new StringBuffer();
String temp;
while ((temp = br.readLine()) != null) {
    response.append(temp);
    response.append("\n");
}
i.设置请求方法时,必须使用大写,如POST,使用post无法识别
ii.如果想要获取错误页面,可以将URLConnection转型为HTTPURLConnection类并调用getErrorStream方法InputStream err = ((HTTPURLConnection) connection).getErrorStream();
URL编码需遵循以下规则:
i.保留字符A-Z、a-z、0-9 以及.-*_
ii.用+替换所有空格
iii.将其他所有字符编码为UTF-8,并将每个字节都编码为%后面紧跟一个两位的十六进制数字
比如发送”New York, NY”,可以使用New+York%2C+NY
四、基于TCP的Socket通信
1.创建ServerSocket和Socket
2.打开连接到Socket的输入/输出流
3.按照协议对Socket进行读/写操作
4.关闭输入/输出流,关闭Socket
服务端(多线程响应多个客户端)
1  | //创建一个服务器端Socket,即ServerSocket,指定绑定的端口,并负责监听此端口  | 
ServerThread类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
    public class ServerThread extends Thread {
	Socket socket = null;
	public ServerThread(Socket socket) {
		this.socket = socket;
	}
	
	//线程执行的操作,响应客户端的请求
	public void run(){
		InputStream is=null;
		InputStreamReader isr=null;
		BufferedReader br=null;
		OutputStream os=null;
		PrintWriter pw=null;
		try {
			//获取输入流,并读取客户端信息
			is = socket.getInputStream();
			isr = new InputStreamReader(is);
			br = new BufferedReader(isr);
			String info=null;
			while((info=br.readLine())!=null){//循环读取客户端的信息
				System.out.println("我是服务器,客户端说:"+info);
			}
			socket.shutdownInput();//关闭输入流,半关闭
			//获取输出流,响应客户端的请求
			os = socket.getOutputStream();
			pw = new PrintWriter(os);
			pw.write("欢迎您!");
			pw.flush();//调用flush()方法将缓冲输出
		} catch (IOException e) {
			e.printStackTrace();
		} finally{
			//关闭资源
			try {
				if(pw!=null)
					pw.close();
				if(os!=null)
					os.close();
				if(br!=null)
					br.close();
				if(isr!=null)
					isr.close();
				if(is!=null)
					is.close();
				if(socket!=null)
					socket.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}
客户端
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//1.创建客户端Socket,指定服务器地址和端口
Socket socket=new Socket("localhost", 8888);
//2.获取输出流,向服务器端发送信息
OutputStream os=socket.getOutputStream();//字节输出流
PrintWriter pw=new PrintWriter(os);//将输出流包装为打印流
pw.write("用户名:alice;密码:789");
pw.flush();
socket.shutdownOutput();//关闭输出流
//3.获取输入流,并读取服务器端的响应信息
InputStream is=socket.getInputStream();
BufferedReader br=new BufferedReader(new InputStreamReader(is));
String info=null;
while((info=br.readLine())!=null){
    System.out.println("我是客户端,服务器说:"+info);
}
//4.关闭资源
br.close();
is.close();
pw.close();
os.close();
socket.close();
五、基于UDP的SOcket通信
1.定义发送信息
2.创建DatagramPacket,包含将要发送的信息
3.创建DatagramSocket
4.发送数据
服务端
- 接收客户端发送的数据
 
1  | //1.创建服务器端DatagramSocket,指定端口  | 
- 向客户端响应数据
 
1  | //1.定义客户端的地址、端口号、数据  | 
客户端
- 向服务器端发送数据
 
1  | //1.定义服务器的地址、端口号、数据  | 
- 接收服务器端响应的数据
 
1  | //1.创建数据报,用于接收服务器端响应的数据  | 
当Socket关闭时,输入输出流也就关闭了