socket用中文意思就是我们常说的”套接字“,我们用它来解决基于TCP/IP协议的网络通信。Java有一套功能强大而又易于使用的网络开发API,这个API是一系列的接口和类,在java.net和javax.net包中可以找到它们。套接字一般分为两种:流套接字(StreamSocket)和数据报套接字(DatagramSockets)。关于套接字的编程可以写成一本书,本文不想在这里做深入探究(其实是本人功力还不够,嘿嘿...),这次主要是了解一下流套接字的基本开发。
一、几个重要的API:
1、InetAddress类
描述:该类在套接字编程中份演着目的地角色,通常作为参数传递给流套接字类和数据报套接字的构造方法或其它方法。
构造方法:该类只有一个默认的不带参的构造方法。
不能直接用new创建一个InetAddress对象。象这样做
InetAddressia = new InetAddress ();
就是错误的。但是我们可以通过它的5个静态工厂方法获得一个InetAddress对象或对象数组。
重要方法:
staticInetAddress[] getAllByName(Stringhost);
通过传递参数host(主机名),返回一个InetAddress对象数组的引用。如果指定的主机没有IP地址存在,则方法抛出一个UnknownHostException异常对象。
staticInetAddress getByAddress(byte[]addr); 通过传递一个用字节数组表示的二进制IP地址参数(4字节对应Ipv4,16字节对应Ipv6),返回一个InetAddress对象的引用。如果返回对象的数组既不是4字节也不是16字节,则方法抛出一个UnknownHostException异常对象。
staticInetAddress getByAddress(String host, byte[]addr); 创建一个基于给定主机名和给定字节数组组成的IP地址的InetAddress对象。如果返回对象中的数组既不是4字节也不是16字节,则方法抛出一个UnknownHostException异常对象。
staticInetAddress getByName(Stringhost); 返回一个与给定主机名的InetAddress对象。如果指定的主机没有IP对应,则方法抛出一个UnknownHostException异常对象。
staticInetAddressgetLocalHost();
返回一个包含本地主机的IP地址的InetAddress对象。
上面讲到的方法均提到返回一个或多个InetAddress对象的引用,实际上每一个方法都要返回一个或多个Inet4Address/Inet6Address对象的引用。一旦获得了InetAddress对象,你就可以使用其他非静态方法得到你想要的东东了。
2、Socket类
描述:Socket是建立网络连接时使用的。在连接成功时,服务端和客户端都会产生一个Socket实例,操作这个实例,完成所需的会话。对于一个网络连接来说,套接字是平等的,并没有差别,不因为在服务器端或在客户端而产生不同级别。
构造方法:该类有多个构造方法,常用的有两个:
Socket(InetAddressaddr, intport) 和
Socket(Stringhost, intport)
两个构造方法都创建了一个基于指定接服务器主机名或InetAddress和服务器端口号的流套接字。对于第一个InetAddress子类对象通过addr参数获得服务器主机的IP地址,对于第二个函数host参数包被分配到InetAddress对象中,如果没有IP地址与host参数相一致,那么将抛出UnknownHostException异常对象。
如果创建连接成功,java网络API将在客户端的流套接字中捆绑客户程序的IP地址和任意一个端口号,否则两个函数都会抛出一个IOException对象。
重要方法:
InputStreamgetInputStream();
获得网络连接输入,同时返回一个IutputStream对象实例。
OutputStreamgetOutputStream(); 获得网络连接输出,连接的另一端将得到输入,同时返回一个OutputStream对象实例。
必须捕获两个方法可能产生的IOException。怎么操作这些流对象就看你要作什么了!:)
3、ServerSocket类
描述:该类用于服务器端。
构造方法:该类有四个构造方法,常用的有:
ServerSocket(intport)
通过指定监听端口号来创建ServerSocket对象,如果在这时出现错误将抛出IOException异常对象,否则将创建ServerSocket对象并开始准备接收连接请求。接下来无限循环调用accept()方法。
重要方法:
Socketaccept();
调用开始后accept()方法将导致调用线程阻塞直到连接建立。在建立连接后accept()返回一个最近创建的Socket对象,该Socket对象绑定了客户程序的IP地址和端口号。
4、注意事项:
在服务端和客户端均未发送数据时,不要在同时在两端的while()循环里读取 InputStream。否则将造成阻塞。
如果用字符流处理数据,请在数据末尾加上“
\r\n”,并记得
flush()一下。
二、实例
1、 服务端 SimpleServerSocket:
例子采用字节流来操作,注释部分是采用字符流来操作。
java 代码
1. package com.unihub.unicall.test;
2.
3. import java.io.IOException;
4. import java.net.ServerSocket;
5.
6. public class SocketServerTest {
7. privateServerSocket server = null;
8. privateintport = 9999;
9. publicSocketServerTest() throwsIOException
10. {
11. intcounter = 1;
12. try
13. {
14. this.server = newServerSocket(this.port);
15. }
16. catch(Exception ex)
17. {
18. System.err.println("Can't listening on port:"+ this.port);
19. ex.printStackTrace(System.err);
20. System.exit(-1);
21. }
22. System.out.println("Start listening on port:"+ this.port);
23. while(true)
24. {
25. newServerThread(server.accept(),counter).start();
26. counter++;
27. }
28. }
29. publicstaticvoidmain(String[] args) throwsException
30. {
31. // SocketServerTest sserver =
32. newSocketServerTest();
33. }
34.
35. }
线程类:
java 代码
1. package com.unihub.unicall.test;
2.
3. import java.io.BufferedInputStream;
4. import java.io.BufferedOutputStream;
5. import java.io.IOException;
6. import java.net.Socket;
7.
8. import com.unihub.unicall.common.util.SocketUtil;
9.
10. public class ServerThread extends Thread {
11. privateSocket client;
12.
13. privateintcounter;
14.
15. publicServerThread(Socket client, intcounter) {
16. System.out.println("[info] Create connection with "
17. + client.getInetAddress().getHostAddress().toString()
18. + " successful.");
19. this.client = client;
20. this.counter = counter;
21. }
22.
23. publicvoidrun() {
24. try{
25. BufferedInputStream bis = newBufferedInputStream(client
26. .getInputStream());
27. BufferedOutputStream bos = newBufferedOutputStream(client
28. .getOutputStream());
29. // BufferedReader in = new BufferedReader(new
30. // InputStreamReader(client.getInputStream()));
31. // PrintWriter out = new PrintWriter(client.getOutputStream(),true);
32.
33. bos.write(("Hi! Enter QUIT to exit.\r\n").getBytes());
34. bos.flush();
35.
36. booleandone = false;
37. byte[] bytes = newbyte[client.getReceiveBufferSize()];
38. while(!done) {
39. intcontentLength = bis.read(bytes);
40.
41. if(contentLength == -1) {
42. System.out.println("contentLength = "+ contentLength);
43. done = true;
44. } else{
45. // String recieve = new String(bytes, 0, contentLength);
46. // if (recieve.trim().equalsIgnoreCase("quit")) {
47. // done = true;
48. // } else {
49. // System.out.println("[info] " + recieve);
50. //
51. // bos
52. // .write(("Echo server(" + counter + "):"
53. // + recieve + "\r\n").getBytes());
54. // bos.flush();
55. // }
56. byte[] b1 = SocketUtil.getSubByte(bytes, 0, 4);
57. byte[] b2 = SocketUtil.getSubByte(bytes, 4, 4);
58. byte[] b3 = SocketUtil.getSubByte(bytes, 20, 257);
59. System.out.println("111111111111:"+SocketUtil.byte2int(b1));
60. System.out.println("报文长度:"+SocketUtil.byte2int(b2));
61. System.out.println("报文内容:"+newString(b3,"ISO-8859-1"));
62. }
63. }
64.
65. // String recieve;
66. // while((recieve = in.readLine()) != null)
67. // {
68. // if(recieve.trim().equalsIgnoreCase("quit")){break;}
69. // else
70. // {
71. // System.out.println("[info] " + recieve);
72. // out.println("Echo server("+ counter +"):" + recieve);
73. // }
74. // }
75. } catch(Exception e) {
76. e.printStackTrace();
77. } finally{
78. try{
79. if(client != null) {
80. client.close();
81. System.out.println("[info] Disconnect successful.");
82. }
83. } catch(IOException e1) {
84. e1.printStackTrace();
85. }
86. }
87. }
88.
89. }
2、 客户端 SimpleSocket:
java 代码
1. package com.cyberobject.socket;
2.
3. import java.io.*;
4. import java.net.*;
5.
6. public class SimpleSocket
7. {
8. privateSocket client;
9. privateString host = "192.168.0.66";
10. privateintport = 30000;
11.
12. publicSimpleSocket()
13. {
14. try
15. {
16. this.client = newSocket(InetAddress.getByName(this.host),this.port);
17.
18. System.out.println("[info] Connect to "+ this.host + " successful.");
19.
20. // BufferedReader in = new BufferedReader(new
21. // InputStreamReader(client.getInputStream()));
22. // PrintWriter out = new PrintWriter(client.getOutputStream(),true);
23. BufferedReader systemIn = newBufferedReader(newInputStreamReader(System.in));
24.
25. BufferedInputStream bis = newBufferedInputStream(client.getInputStream());
26. BufferedOutputStream bos = newBufferedOutputStream(client.getOutputStream());
27.
28. System.out.println("[info] Start...");
29.
30. booleandone = false;
31. // while(!done)
32. // {
33. // String recieve = in.readLine();
34. // if(recieve == null) done = true;
35. // else
36. // {
37. // System.out.println(recieve);
38. // out.println(systemIn.readLine());
39. // }
40. // }
41.
42. byte[] bytes = newbyte[client.getReceiveBufferSize()];
43. intlen = 0;
44. while(!done)
45. {
46. len = bis.read(bytes);
47. if(len == -1) done = true;
48. else
49. {
50. String recieve = newString(bytes, 0, len);
51.
52. System.out.println(recieve);
53. bos.write(systemIn.readLine().getBytes());
54. bos.flush();
55. }
56. }
57.
58. System.out.println("[info] Stop.");
59. }
60. catch(Exception ex)
61. {
62. ex.printStackTrace(System.err);
63. }
64. finally
65. {
66. try
67. {
68. if(client != null)
69. {
70. client.close();
71. }
72. }
73. catch(IOException e)
74. {
75. e.printStackTrace();
76. }
77. }
78. }
79.
80. publicstaticvoidmain(String[] args)
81. {
82. SimpleSocket ssocket = newSimpleSocket();
83. }
84. }