/**
* Create a new session and connect to jabber server host denoted by
* <code>route</code> or <code>to</code>.
*
* @param to
* domain of the server to connect to.
* @param route
* optional hostname of the server to connect to (might be null).
*
* @throws UnknownHostException
* @throws IOException
*/
public Session(String to, String route) throws UnknownHostException,
IOException {
this.to = to;
int port = DEFAULT_XMPPPORT;
this.sock = new Socket();
this.setLastActive();
try {
this.db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
} catch (Exception e) {
}
// first, try connecting throught the 'route' attribute.
if (route != null && !route.equals("")) {
JHBServlet.dbg(
"Trying to use 'route' attribute to open a socket...", 3);
if (route.startsWith("xmpp:")) {
route = route.substring("xmpp:".length());
}
int i;
// has 'route' the optional port?
if ((i = route.lastIndexOf(":")) != -1) {
try {
int p = Integer.parseInt(route.substring(i + 1));
if (p >= 0 && p <= 65535) {
port = p;
JHBServlet.dbg(
"...route attribute holds a valid port ("
+ port + ").", 3);
}
} catch (NumberFormatException nfe) {
}
route = route.substring(0, i);
}
JHBServlet.dbg("Trying to open a socket to '" + route
+ "', using port " + port + ".", 3);
try {
this.sock.connect(new InetSocketAddress(route, port),
SOCKET_TIMEOUT);
} catch (Exception e) {
JHBServlet.dbg(
"Failed to open a socket using the 'route' attribute",
3);
/*
* none of the exceptions possible should be reason to throw
* anything. If the socket isn't opened, we'll get a retry using
* the 'to' attribute anyway.
*/
}
}
// If no socket has been opened, try connecting trough the 'to'
// attribute.
if (this.sock == null || !this.sock.isConnected()) {
JHBServlet.dbg("Trying to use 'to' attribute to open a socket...",
3);
host = DNSUtil.resolveXMPPServerDomain(to, DEFAULT_XMPPPORT);
try {
JHBServlet.dbg("Trying to open a socket to '" + host.getHost()
+ "', using port " + host.getPort() + ".", 3);
this.sock.connect(new InetSocketAddress(host.getHost(), host
.getPort()), SOCKET_TIMEOUT);
} catch (UnknownHostException uhe) {
JHBServlet.dbg(
"Failed to open a socket using the 'to' attribute", 3);
throw uhe;
} catch (IOException ioe) {
JHBServlet.dbg(
"Failed to open a socket using the 'to' attribute", 3);
throw ioe;
}
}
// at this point, we either have a socket, or an exception has already
// been thrown.
try {
if (this.sock.isConnected())
JHBServlet.dbg("Succesfully connected to " + to, 2);
this.sock.setSoTimeout(SOCKET_TIMEOUT);
// instantiate <stream>
this.osw = new OutputStreamWriter(this.sock.getOutputStream(),
"UTF-8");
this.osw.write("<stream:stream to='" + this.to + "'"
+ " xmlns='jabber:client' "
+ " xmlns:stream='http://etherx.jabber.org/streams'"
+ " version='1.0'" + ">");
this.osw.flush();
// create unique session id
while (sessions.get(this.sid = createSessionID(24)) != null)
;
JHBServlet.dbg("creating session with id " + this.sid, 2);
// register session
sessions.put(this.sid, this);
// create list of responses
responses = new TreeMap();
this.br = new BufferedReader(new InputStreamReader(this.sock
.getInputStream(), "UTF-8"));
this.streamPattern = Pattern.compile(
".*<stream:stream[^>]*id=['|\"]([^'|^\"]+)['|\"][^>]*>.*",
Pattern.DOTALL);
this.stream10Pattern = Pattern
.compile(
".*<stream:stream[^>]*id=['|\"]([^'|^\"]+)['|\"][^>]*>.*(<stream.*)$",
Pattern.DOTALL);
this.stream10Test = Pattern.compile(
".*<stream:stream[^>]*version=['|\"]1.0['|\"][^>]*>.*",
Pattern.DOTALL);
this.setStatus(SESS_ACTIVE);
} catch (IOException ioe) {
throw ioe;
}
}
整个构造方法的作用是创建一个新的 session 并且连接到 jabber 服务器上去。 Create a new session and connect to jabber server host denoted by <code> route </code> or <code> to </code> .
这是 Session 类的构造方法,带两个 String 类型的参数 to 和 route ,分别都表示与之建立会话的 Server ,而 route 是备用可选的: optional hostname of the server to connect to (might be null) 。
this . sock = new Socket();
this .setLastActive();
创建一个 Socket 对象,并且在此时 setLastActive ,因为他认为创建 Socket 对象算是 Active 动作吧。
// first, try connecting throught the 'route' attribute.
if (route != null && !route.equals("")) {
JHBServlet.dbg(
"Trying to use 'route' attribute to open a socket...", 3);
if (route.startsWith("xmpp:")) {
route = route.substring("xmpp:".length());
}
int i;
// has 'route' the optional port?
if ((i = route.lastIndexOf(":")) != -1) {
try {
int p = Integer.parseInt(route.substring(i + 1));
if (p >= 0 && p <= 65535) {
port = p;
JHBServlet.dbg(
"...route attribute holds a valid port ("
+ port + ").", 3);
}
} catch (NumberFormatException nfe) {
}
route = route.substring(0, i);
}
JHBServlet.dbg("Trying to open a socket to '" + route
+ "', using port " + port + ".", 3);
try {
this.sock.connect(new InetSocketAddress(route, port),
SOCKET_TIMEOUT);
} catch (Exception e) {
JHBServlet.dbg(
"Failed to open a socket using the 'route' attribute",
3);
/*
* none of the exceptions possible should be reason to throw
* anything. If the socket isn't opened, we'll get a retry using
* the 'to' attribute anyway.
*/
}
}
接下来,试着用 route 来连接,结合下面的程序可以看出 route 的构成是这样的 xmpp:domain:port ,所以最终 socket 连接也是这样连的:
this.sock.connect(new InetSocketAddress(route, port),
SOCKET_TIMEOUT);
// If no socket has been opened, try connecting trough the 'to'
// attribute.
if (this.sock == null || !this.sock.isConnected()) {
JHBServlet.dbg("Trying to use 'to' attribute to open a socket...",
3);
host = DNSUtil.resolveXMPPServerDomain(to, DEFAULT_XMPPPORT);
try {
JHBServlet.dbg("Trying to open a socket to '" + host.getHost()
+ "', using port " + host.getPort() + ".", 3);
this.sock.connect(new InetSocketAddress(host.getHost(), host
.getPort()), SOCKET_TIMEOUT);
} catch (UnknownHostException uhe) {
JHBServlet.dbg(
"Failed to open a socket using the 'to' attribute", 3);
throw uhe;
} catch (IOException ioe) {
JHBServlet.dbg(
"Failed to open a socket using the 'to' attribute", 3);
throw ioe;
}
}
接下来用 to 来连接,而对 to 的解析采用了封装的 resolveXMPPServerDomain 方法,得到的 DNSUtil.HostAddress 对象
// at this point, we either have a socket, or an exception // has already been thrown.
到此我们或者有了 socket 或者是一个已经抛出的 exception
if (this.sock.isConnected())
JHBServlet.dbg("Succesfully connected to " + to, 2);
this.sock.setSoTimeout(SOCKET_TIMEOUT);
// instantiate <stream>
this.osw = new OutputStreamWriter(this.sock.getOutputStream(),
"UTF-8");
this.osw.write("<stream:stream to='" + this.to + "'"
+ " xmlns='jabber:client' "
+ " xmlns:stream='http://etherx.jabber.org/streams'"
+ " version='1.0'" + ">");
this.osw.flush();
首先向 OutputStreamWriter 流中写数据。
// create unique session id
while (sessions.get(this.sid = createSessionID(24)) != null);
接着创建一个独特的 session id ,这里的 sessions 是一个 HashTable ,如果对应 key 所得不为 null ,即表重复,循取。
// register session
sessions.put(this.sid, this);
取得 unique sid 之后,记得存入。接下去是一些 Pattern 对象的建立,最后:
this.setStatus(SESS_ACTIVE);
表明到此处 session 是处于活动状态的。 Sid 型如: terminating session WOfs8pYb5UEpttRISjjS1Uxc