导读:
说明:以下是实现代码,关于msn协议的分析请参考http://www.cnpaf.net/Forum/viewthread.php?tid=1761。
这里只考虑了如何实现msn发消息的功能,至于面向对象,线程之类的暂时没考虑那么多,大家就将就一下了。。。
1.主类:
/**
* Author EvilgoD
* QQ:7771465
* blog:http://evilgod.javaeye.com
* Date 2008-1-8
*/
public class MyMSN{
public static void main(String []args) throws Exception {
String username="urname@xxx.com";
String password="urpsw";
String remoteusername="urfriend@xxx.com";
String instantmessage="test!";
MSNServer server=new MSNServer(username,password);
server.login();
server.setStatus();
server.send(remoteusername,instantmessage);
server.close();
}
}
2. MSNServer类:
/**
* Author EvilgoD
* QQ:7771465
* blog:http://evilgod.javaeye.com
* Date 2008-1-8
*/
import java.io.*;
import java.net.*;
import java.util.*;
import java.security.*;
import javax.net.ssl.*;
public class MSNServer{
public String username,password;
private int command=0;//流水号
private Socket server;
private PrintWriter out;
private MSNFilterStream in;
public String temp;
public MSNServer(String username,String password){
this.username=username;
this.password=password;
}
//登录
public void login() throws Exception{
server = new Socket("messenger.hotmail.com", 1863);
server.setTrafficClass(0x10);
out = new PrintWriter(server.getOutputStream(), true);
in=new MSNFilterStream(new BufferedInputStream(server.getInputStream()));
//报告协议号
message="VER "+command+" MSN10 MSNP9 CVRO ";
out.println(message);
command++;
temp=in.readLine();
System.out.println(temp);
//报告本机消息
message="CVR "+command+" 0x0804 winnt 5.2 i386 MSNMSGR 7.5.0299 MSMSGS "+username+" ";
out.println(message);
command++;
temp=in.readLine();
System.out.println(temp);
//提交登录用户名
message="USR "+command+" TWN I "+username+" ";
out.println(message);
command++;
temp=in.readLine();
System.out.println(temp);
//连接到ns服务器
StringTokenizer st=new StringTokenizer(temp);
st.nextToken();st.nextToken();st.nextToken();
String ns=st.nextToken();//NS地址
out.close();//关闭与DS服务器的连接
in.close();
server.close();
String []split=ns.split(":");
server=new Socket(split[0],Integer.parseInt(split[1]));
server.setTrafficClass(0x10);
out = new PrintWriter(server.getOutputStream(), true);
in=new MSNFilterStream(new BufferedInputStream(server.getInputStream()));
message="VER "+command+" MSN10 MSNP9 CVR0";
command++;
out.println(message);
temp=in.readLine();
System.out.println(temp);
//报告本机信息
message="CVR "+command+" 0x0804 winnt 5.2 i386 MSNMSGR 7.5.0299 MSMSGS "+username+" ";
out.println(message);
command++;
temp=in.readLine();
//发送用户信息
message="USR "+command+" TWN I "+username+" ";
out.println(message);
command++;
//!验证登录信息,首先在HTTPS端口443向nexus.passport.com发送一个GET请求,将账号、密码和NS给定的一长串信息送出
temp=in.readLine();
System.out.println(temp);
st=new StringTokenizer(temp);
st.nextToken();st.nextToken();st.nextToken();st.nextToken();
String args=st.nextToken();
Socket login = new Socket("nexus.passport.com", 443);
login = ((SSLSocketFactory)SSLSocketFactory.getDefault()).createSocket(login, "nexus.passport.com", 443, true);
BufferedReader readin = new BufferedReader(new InputStreamReader(new LogInputStream(login.getInputStream())));
PrintWriter printout = new PrintWriter(login.getOutputStream(), true);
printout.println("GET /rdr/pprdr.asp");
String host = null;
String get = null;
String data = readin.readLine();
while (data != null) {
System.out.println(data);
if (data.startsWith("PassportURLs:")) {
data = data.substring(14);
StringTokenizer tok = new StringTokenizer(data, ",");
while (tok.hasMoreTokens()) {
String tmp = tok.nextToken();
if (tmp.startsWith("DALogin=")) {
tmp = tmp.substring(8);
host = tmp.substring(0, tmp.indexOf("/"));
get = tmp.substring(tmp.indexOf("/"));
}
}
}
data = readin.readLine();
}
boolean redirect = true;
String auth = null;
//根据情况,会重定向到不同的URL;然后,重新向指定的URL发出请求
while (redirect) {
redirect = false;
login = new Socket(host, 443);
login = ((SSLSocketFactory)SSLSocketFactory.getDefault()).createSocket(login, host, 443, true);
readin = new BufferedReader(new InputStreamReader(login.getInputStream()));
printout = new PrintWriter(login.getOutputStream(), true);
StringBuffer buf = new StringBuffer();
buf.append("GET ");
buf.append(get);
buf.append(" HTTP/1.1/r/n");
buf.append("Authorization: ");
buf.append("Passport1.4 OrgVerb=GET,OrgURL=http%3A%2F%2Fmessenger%2Emsn%2Ecom,sign-in=");
try {
buf.append(encode(URLEncoder.encode(username, "UTF-8")));
buf.append(",pwd=");
buf.append(encode(URLEncoder.encode(password, "UTF-8")));
} catch (Exception e) {
e.printStackTrace();
return;
}
buf.append(",");
buf.append(args);
buf.append("/r/nHost: ");
buf.append(host);
buf.append("/r/n");
System.out.println("Get - "+buf.toString());
printout.println(buf.toString());
data = readin.readLine();
while (data != null) {
System.out.println(data);
if (data.startsWith("Location:")) {
redirect = true;
host = data.substring(data.indexOf("://")+3);
get = host.substring(host.indexOf("/"));
host = host.substring(0, host.indexOf("/"));
} else if (data.startsWith("Authentication-Info: ")) {
StringTokenizer tok = new StringTokenizer(data.substring(data.indexOf("da-status=")), ",");
while (tok.hasMoreTokens()) {
data = tok.nextToken();
if (data.startsWith("from-PP=")) {
auth = data.substring(9, data.length()-1);
}
}
}
data = readin.readLine();
}
}
//声明、传递、鉴别用户身份
message="USR "+command+" TWN S "+auth;
System.out.println(message);
out.println(message);
temp=in.readLine();
System.out.println(temp);
}
//设置状态
public void setStatus() throws Exception{
//要求改变状态
message="CHG "+command+" NLN";
out.println(message);
temp=in.readLine();
while(!temp.startsWith("CHL")){
temp=in.readLine();
System.out.println(temp);
}
//客户端回答服务器的验证要求
StringTokenizer st=new StringTokenizer(temp);
st.nextToken();
message="QRY "+command+" msmsgs@msnmsgr.com 32";
out.println(message);
st.nextToken();
String hash=st.nextToken();
String enc = hash+"Q1P7W2E4J9R8U3S5";
MessageDigest digest = MessageDigest.getInstance("MD5");
enc = byteArrayToHexString(digest.digest(enc.getBytes()));
out.print(enc);
out.flush();
temp=in.readLine();
System.out.println("here:"+temp);
}
//发送消息
public boolean send(String remoteusername,String instantmessage) throws Exception{
String rusername=remoteusername;
String imessage=instantmessage;
//询问转接服务器在哪
message="XFR "+command+" SB";
out.println(message);
command++;
temp=in.readLine();
System.out.println(temp);
if(!temp.startsWith("XFR")) return false;
//连接转接服务器
StringTokenizer st=new StringTokenizer(temp);
int cmd=0;
st.nextToken();st.nextToken();st.nextToken();
String []split=st.nextToken().split(":");
Socket swtserver=new Socket(split[0],Integer.parseInt(split[1]));//转接服务器
swtserver.setTrafficClass(0x10);
st.nextToken();
message="USR "+cmd+" "+username+" "+st.nextToken();
cmd++;
System.out.println(message);
PrintWriter swtout=new PrintWriter(swtserver.getOutputStream(),true);
MSNFilterStream swtin=new MSNFilterStream(new BufferedInputStream(swtserver.getInputStream()));
swtout.println(message);
temp=swtin.readLine();
System.out.println(temp);
//发送消息
System.out.println("发送消息");
message="CAL "+cmd+" "+rusername;
cmd++;
swtout.println(message);
System.out.println(message);
temp=swtin.readLine();
System.out.println(temp);
temp=swtin.readLine();
System.out.println(temp);
if(!temp.startsWith("JOI")) return false;
String txt= "MIME-Version: 1.0/r/n";
txt=txt+"Content-Type: text/x-msmsgscontrol/r/n"+"TypingUser: "+username+"/r/n/r/n/r/n";
message="MSG "+cmd+" U"+" "+txt.length()+ "/r/n" + txt;
cmd++;
System.out.println(message);
swtout.print(message);
swtout.flush();
txt = "MIME-Version: 1.0/r/n";
txt = txt+"Content-Type: text/plain; charset=UTF-8/r/n"+
"X-MMS-IM-Format: FN=%E5%AE%8B%E4%BD%93; EF=; CO=0; CS=86; PF=0/r/n/r/n"+imessage;
message="MSG "+cmd+" N"+" "+txt.length()+ "/r/n" + txt;
System.out.println(message);
swtout.print(message);
swtout.flush();
temp=swtin.readLine();
System.out.println(temp);
swtin.close();
swtout.close();
return true;
}
//退出
public void close() throws Exception{
flag=false;
in.close();
out.close();
}
private static String encode(String encodedString) {
String data;
for (int i = 0; i
if ( encodedString.charAt(i) == '+' ) {
data = encodedString.substring(0, i);
data += "%20" + encodedString.substring(i+1);
encodedString = data;
}
}
return encodedString;
}
private static String byteArrayToHexString (byte[] bytes) {
String hexString = "";
for (int i = 0; i byte b = bytes[i];
hexString = hexString + byteToHexString(b &0xf, (b >> 4) &0xf);
}
return hexString;
}
private static String byteToHexString (int nib1, int nib2) {
char char1, char2;
char1 = nibbleToChar (nib1);
char2 = nibbleToChar (nib2);
char[] chars = new char[2];
chars[0] = char2;
chars[1] = char1;
return (new String (chars));
}
private static char nibbleToChar (int nibble) {
if (nibble <10) {
return (Integer.toString (nibble)).charAt(0);
} else {
int nib = nibble - 10;
return (char)(((char) nib) + 'a');
}
}
}
3. LogInputStream类
/**
* Author EvilgoD
* QQ:7771465
* blog:http://evilgod.javaeye.com
* Date 2008-1-8
*/
import java.io.IOException;
import java.io.InputStream;
class LogInputStream extends InputStream {
private InputStream in;
public LogInputStream(InputStream in) {
this.in = in;
}
public int read() throws IOException {
int value = in.read();
return value;
}
public int available() throws IOException {
return in.available();
}
public int read(byte[] b) throws IOException {
int value = in.read(b);
return value;
}
public int read(byte[] b, int off, int len) throws IOException {
int value = in.read(b, off, len);
return value;
}
public void close() throws IOException {
in.close();
}
}
4. MSNFilterStream类
/**
* Author EvilgoD
* QQ:7771465
* blog:http://evilgod.javaeye.com
* Date 2008-1-8
*/
import java.io.ByteArrayOutputStream;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
class MSNFilterStream extends FilterInputStream{
public MSNFilterStream(InputStream in) {
super(in);
}
public String readLine() throws IOException {
boolean prevReturn = false;
ByteArrayOutputStream b = new ByteArrayOutputStream(128);
while(true) {
int value = this.in.read();
if (value<0)
return "null";
if (value=='/r') {
if (prevReturn) {
b.write('/r');
} else {
prevReturn = true;
}
} else {
if (value == '/n') {
// we are ready, we get /r/n
return new String(b.toByteArray(),"UTF-8");
} else {
prevReturn = false;
b.write(value);
}
}
}
}
}
说明:以下是实现代码,关于msn协议的分析请参考http://www.cnpaf.net/Forum/viewthread.php?tid=1761。
这里只考虑了如何实现msn发消息的功能,至于面向对象,线程之类的暂时没考虑那么多,大家就将就一下了。。。
1.主类:
/**
* Author EvilgoD
* QQ:7771465
* blog:http://evilgod.javaeye.com
* Date 2008-1-8
*/
public class MyMSN{
public static void main(String []args) throws Exception {
String username="urname@xxx.com";
String password="urpsw";
String remoteusername="urfriend@xxx.com";
String instantmessage="test!";
MSNServer server=new MSNServer(username,password);
server.login();
server.setStatus();
server.send(remoteusername,instantmessage);
server.close();
}
}
2. MSNServer类:
/**
* Author EvilgoD
* QQ:7771465
* blog:http://evilgod.javaeye.com
* Date 2008-1-8
*/
import java.io.*;
import java.net.*;
import java.util.*;
import java.security.*;
import javax.net.ssl.*;
public class MSNServer{
public String username,password;
private int command=0;//流水号
private Socket server;
private PrintWriter out;
private MSNFilterStream in;
public String temp;
public MSNServer(String username,String password){
this.username=username;
this.password=password;
}
//登录
public void login() throws Exception{
server = new Socket("messenger.hotmail.com", 1863);
server.setTrafficClass(0x10);
out = new PrintWriter(server.getOutputStream(), true);
in=new MSNFilterStream(new BufferedInputStream(server.getInputStream()));
//报告协议号
message="VER "+command+" MSN10 MSNP9 CVRO ";
out.println(message);
command++;
temp=in.readLine();
System.out.println(temp);
//报告本机消息
message="CVR "+command+" 0x0804 winnt 5.2 i386 MSNMSGR 7.5.0299 MSMSGS "+username+" ";
out.println(message);
command++;
temp=in.readLine();
System.out.println(temp);
//提交登录用户名
message="USR "+command+" TWN I "+username+" ";
out.println(message);
command++;
temp=in.readLine();
System.out.println(temp);
//连接到ns服务器
StringTokenizer st=new StringTokenizer(temp);
st.nextToken();st.nextToken();st.nextToken();
String ns=st.nextToken();//NS地址
out.close();//关闭与DS服务器的连接
in.close();
server.close();
String []split=ns.split(":");
server=new Socket(split[0],Integer.parseInt(split[1]));
server.setTrafficClass(0x10);
out = new PrintWriter(server.getOutputStream(), true);
in=new MSNFilterStream(new BufferedInputStream(server.getInputStream()));
message="VER "+command+" MSN10 MSNP9 CVR0";
command++;
out.println(message);
temp=in.readLine();
System.out.println(temp);
//报告本机信息
message="CVR "+command+" 0x0804 winnt 5.2 i386 MSNMSGR 7.5.0299 MSMSGS "+username+" ";
out.println(message);
command++;
temp=in.readLine();
//发送用户信息
message="USR "+command+" TWN I "+username+" ";
out.println(message);
command++;
//!验证登录信息,首先在HTTPS端口443向nexus.passport.com发送一个GET请求,将账号、密码和NS给定的一长串信息送出
temp=in.readLine();
System.out.println(temp);
st=new StringTokenizer(temp);
st.nextToken();st.nextToken();st.nextToken();st.nextToken();
String args=st.nextToken();
Socket login = new Socket("nexus.passport.com", 443);
login = ((SSLSocketFactory)SSLSocketFactory.getDefault()).createSocket(login, "nexus.passport.com", 443, true);
BufferedReader readin = new BufferedReader(new InputStreamReader(new LogInputStream(login.getInputStream())));
PrintWriter printout = new PrintWriter(login.getOutputStream(), true);
printout.println("GET /rdr/pprdr.asp");
String host = null;
String get = null;
String data = readin.readLine();
while (data != null) {
System.out.println(data);
if (data.startsWith("PassportURLs:")) {
data = data.substring(14);
StringTokenizer tok = new StringTokenizer(data, ",");
while (tok.hasMoreTokens()) {
String tmp = tok.nextToken();
if (tmp.startsWith("DALogin=")) {
tmp = tmp.substring(8);
host = tmp.substring(0, tmp.indexOf("/"));
get = tmp.substring(tmp.indexOf("/"));
}
}
}
data = readin.readLine();
}
boolean redirect = true;
String auth = null;
//根据情况,会重定向到不同的URL;然后,重新向指定的URL发出请求
while (redirect) {
redirect = false;
login = new Socket(host, 443);
login = ((SSLSocketFactory)SSLSocketFactory.getDefault()).createSocket(login, host, 443, true);
readin = new BufferedReader(new InputStreamReader(login.getInputStream()));
printout = new PrintWriter(login.getOutputStream(), true);
StringBuffer buf = new StringBuffer();
buf.append("GET ");
buf.append(get);
buf.append(" HTTP/1.1/r/n");
buf.append("Authorization: ");
buf.append("Passport1.4 OrgVerb=GET,OrgURL=http%3A%2F%2Fmessenger%2Emsn%2Ecom,sign-in=");
try {
buf.append(encode(URLEncoder.encode(username, "UTF-8")));
buf.append(",pwd=");
buf.append(encode(URLEncoder.encode(password, "UTF-8")));
} catch (Exception e) {
e.printStackTrace();
return;
}
buf.append(",");
buf.append(args);
buf.append("/r/nHost: ");
buf.append(host);
buf.append("/r/n");
System.out.println("Get - "+buf.toString());
printout.println(buf.toString());
data = readin.readLine();
while (data != null) {
System.out.println(data);
if (data.startsWith("Location:")) {
redirect = true;
host = data.substring(data.indexOf("://")+3);
get = host.substring(host.indexOf("/"));
host = host.substring(0, host.indexOf("/"));
} else if (data.startsWith("Authentication-Info: ")) {
StringTokenizer tok = new StringTokenizer(data.substring(data.indexOf("da-status=")), ",");
while (tok.hasMoreTokens()) {
data = tok.nextToken();
if (data.startsWith("from-PP=")) {
auth = data.substring(9, data.length()-1);
}
}
}
data = readin.readLine();
}
}
//声明、传递、鉴别用户身份
message="USR "+command+" TWN S "+auth;
System.out.println(message);
out.println(message);
temp=in.readLine();
System.out.println(temp);
}
//设置状态
public void setStatus() throws Exception{
//要求改变状态
message="CHG "+command+" NLN";
out.println(message);
temp=in.readLine();
while(!temp.startsWith("CHL")){
temp=in.readLine();
System.out.println(temp);
}
//客户端回答服务器的验证要求
StringTokenizer st=new StringTokenizer(temp);
st.nextToken();
message="QRY "+command+" msmsgs@msnmsgr.com 32";
out.println(message);
st.nextToken();
String hash=st.nextToken();
String enc = hash+"Q1P7W2E4J9R8U3S5";
MessageDigest digest = MessageDigest.getInstance("MD5");
enc = byteArrayToHexString(digest.digest(enc.getBytes()));
out.print(enc);
out.flush();
temp=in.readLine();
System.out.println("here:"+temp);
}
//发送消息
public boolean send(String remoteusername,String instantmessage) throws Exception{
String rusername=remoteusername;
String imessage=instantmessage;
//询问转接服务器在哪
message="XFR "+command+" SB";
out.println(message);
command++;
temp=in.readLine();
System.out.println(temp);
if(!temp.startsWith("XFR")) return false;
//连接转接服务器
StringTokenizer st=new StringTokenizer(temp);
int cmd=0;
st.nextToken();st.nextToken();st.nextToken();
String []split=st.nextToken().split(":");
Socket swtserver=new Socket(split[0],Integer.parseInt(split[1]));//转接服务器
swtserver.setTrafficClass(0x10);
st.nextToken();
message="USR "+cmd+" "+username+" "+st.nextToken();
cmd++;
System.out.println(message);
PrintWriter swtout=new PrintWriter(swtserver.getOutputStream(),true);
MSNFilterStream swtin=new MSNFilterStream(new BufferedInputStream(swtserver.getInputStream()));
swtout.println(message);
temp=swtin.readLine();
System.out.println(temp);
//发送消息
System.out.println("发送消息");
message="CAL "+cmd+" "+rusername;
cmd++;
swtout.println(message);
System.out.println(message);
temp=swtin.readLine();
System.out.println(temp);
temp=swtin.readLine();
System.out.println(temp);
if(!temp.startsWith("JOI")) return false;
String txt= "MIME-Version: 1.0/r/n";
txt=txt+"Content-Type: text/x-msmsgscontrol/r/n"+"TypingUser: "+username+"/r/n/r/n/r/n";
message="MSG "+cmd+" U"+" "+txt.length()+ "/r/n" + txt;
cmd++;
System.out.println(message);
swtout.print(message);
swtout.flush();
txt = "MIME-Version: 1.0/r/n";
txt = txt+"Content-Type: text/plain; charset=UTF-8/r/n"+
"X-MMS-IM-Format: FN=%E5%AE%8B%E4%BD%93; EF=; CO=0; CS=86; PF=0/r/n/r/n"+imessage;
message="MSG "+cmd+" N"+" "+txt.length()+ "/r/n" + txt;
System.out.println(message);
swtout.print(message);
swtout.flush();
temp=swtin.readLine();
System.out.println(temp);
swtin.close();
swtout.close();
return true;
}
//退出
public void close() throws Exception{
flag=false;
in.close();
out.close();
}
private static String encode(String encodedString) {
String data;
for (int i = 0; i
if ( encodedString.charAt(i) == '+' ) {
data = encodedString.substring(0, i);
data += "%20" + encodedString.substring(i+1);
encodedString = data;
}
}
return encodedString;
}
private static String byteArrayToHexString (byte[] bytes) {
String hexString = "";
for (int i = 0; i byte b = bytes[i];
hexString = hexString + byteToHexString(b &0xf, (b >> 4) &0xf);
}
return hexString;
}
private static String byteToHexString (int nib1, int nib2) {
char char1, char2;
char1 = nibbleToChar (nib1);
char2 = nibbleToChar (nib2);
char[] chars = new char[2];
chars[0] = char2;
chars[1] = char1;
return (new String (chars));
}
private static char nibbleToChar (int nibble) {
if (nibble <10) {
return (Integer.toString (nibble)).charAt(0);
} else {
int nib = nibble - 10;
return (char)(((char) nib) + 'a');
}
}
}
3. LogInputStream类
/**
* Author EvilgoD
* QQ:7771465
* blog:http://evilgod.javaeye.com
* Date 2008-1-8
*/
import java.io.IOException;
import java.io.InputStream;
class LogInputStream extends InputStream {
private InputStream in;
public LogInputStream(InputStream in) {
this.in = in;
}
public int read() throws IOException {
int value = in.read();
return value;
}
public int available() throws IOException {
return in.available();
}
public int read(byte[] b) throws IOException {
int value = in.read(b);
return value;
}
public int read(byte[] b, int off, int len) throws IOException {
int value = in.read(b, off, len);
return value;
}
public void close() throws IOException {
in.close();
}
}
4. MSNFilterStream类
/**
* Author EvilgoD
* QQ:7771465
* blog:http://evilgod.javaeye.com
* Date 2008-1-8
*/
import java.io.ByteArrayOutputStream;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
class MSNFilterStream extends FilterInputStream{
public MSNFilterStream(InputStream in) {
super(in);
}
public String readLine() throws IOException {
boolean prevReturn = false;
ByteArrayOutputStream b = new ByteArrayOutputStream(128);
while(true) {
int value = this.in.read();
if (value<0)
return "null";
if (value=='/r') {
if (prevReturn) {
b.write('/r');
} else {
prevReturn = true;
}
} else {
if (value == '/n') {
// we are ready, we get /r/n
return new String(b.toByteArray(),"UTF-8");
} else {
prevReturn = false;
b.write(value);
}
}
}
}
}