在java中提供了一系列的访问网络资源的工具类,在学习理解Scoket(套接字编程)时首先需要了解俩个东西:
1:TCP/IP和IP
为了进行网络通信,通信双方必须遵守通信协议.目前最广泛使用的是TCP/IP协议,它是Internet中各方所遵循的公共协 议.TCP(Transport Control Protocol)是一种传输控制协议,IP(Internet Protocol)是一种网际协议(代表计算机的地址), TCP/IP代表这两个协议的。
2:InetAddress类
Java.net包中有InetAddress类的定义,InetAddress类的对象用于IP地址和域名,该类提供以下方法:
getByName(String s):获得一个InetAddress 类的对象,该对象中含有主机的IP地址和域名,该对象用如下格式表示它包含 的信息: www.baidu.com/202.108.37.40;
String getHostName():获取InetAddress对象的域名;
String getHostAddress():获取InetAddress对象的IP地址;
getLocalHost():获得一个InetAddress对象,该对象含有本地机的域名和IP地址。
如:
InetAddress addr = InetAddress.getByname(“www.baidu.com”);
String domainName = addr.getHostName();//获得主机名
String IPName = addr.getHostAddress();//获得IP地址
System.out.println(domainName);
System.out.println(IPName);
输出结果为:www.baidu.com \n 180.97.33.107
3:socket基础
3.1 网络应用模式主要有:
3.1.1:主机/终端模式:集中计算,集中管理;
3.1.2:客户机/服务器(Client/Server,简称C/S)模式:分布计算,分布管理;
3.1.3:浏览器/服务器模式:利用Internet跨平台。
在客户机/服务器工作模式中,在Server端,要准备接受多个Client端计算机的通信。为此,除用IP地址标识Internet上的计算机 之外,另还引入端口号,用端口号标识正在Server端后台服务的线程。端口号与IP地址的组合称为网络套接字(socket)。
3.2 Java语言在实现C/S模式中,套接字分为两类:
在Server端,ServerSocket类支持底层的网络通信;
在Client端,Socket类支持网络的底层通信。
Server机通过端口(总线I/O地址)提供面向Client机的服务;Server机在它的几个不同端口分别同时提供几种不同的服务。 Client接入Server的某一端口,通过这个端口提请Server机为其服务。
规定:端口号0~1023供系统专用。例如,HTTP协议在端口80,telnet协议在端口23。端口1024~65535供应用程序使用。
3.3 具体使用
3.3.1:新建客户端,使用Socket请求连接指定IP和port端口的服务器
3.3.2:新建服务端,响应客户端的连接请求
说明:ip是是本机的地址,port端口号是认为约定的,server.accept()是一个阻塞式方法,当有客户端连接进来才会往下执 行。也就是当有客户端连接到服务端的时候,socket就不为空了。
以上代码能够把客户端和服务端之间建立连接,但是在实际项目中需要客户端和服务端进行通信,具体需求为客户端读取控制台 输入的字符串发送到服务端,service接受客户端的消息,打印在控制台,并且恢复client客户端消息,客户端接收恢复消息也打 印在控制台。
具体实现如下:
Client(客户端)
public static void main(String[] args) {
// TODO Auto-generated method stub
Socket socket = null;//Socket套接字
PrintWriter os = null; //输出类
BufferedReader br=null;//字符拂去缓冲流
try {
// 实例化一个Socket套接字,向IP为127.0.0.1 端口为9086的机子发起会话
socket = new Socket(host, port);
// 实例化一个消息读取线程
new ClientreadMsg(socket).start();
os=new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())));
// 由Socket对象得到输入流,并构造相应的BufferedReader对象
// 由系统标准输入设备构造BufferedReader对象 字符读取
//InputStreamReader 把字节流转成字符流
br = new BufferedReader(new InputStreamReader(System.in));
String readline;
while (true) {
readline=br.readLine();
if (!readline.equalsIgnoreCase("bye")) {
// 若从标准输入读入的字符串为 "yes"则停止循环
// 将从系统标准输入读入的字符串输出到Server
os.println(readline);
// 刷新输出流,使Server马上收到该字符串
os.flush();
System.out.println("(提示:客户端发送到服务器的消息发送成功!
正在等待服务器返回消息,请稍候....)");
}else{
break;
}
}
} catch (Exception e) {
System.out.print(e.toString());
} finally {
System.out.println("关闭");
try {
os.close(); // 关闭Socket输出流
br.close(); // 关闭Socket输入流
socket.close(); // 关闭Socket
} catch (Exception e) {
}
}
}
客户端中的ClientreadMsg类:主要书为了读取服务端发来的消息
public class ClientreadMsg extends Thread {
//套接字对象
private Socket socket = null;
//有socket实例化的BufferedReader
private BufferedReader is =null;
//当前线程是否正在工作
public static boolean is_taking=false;
//通过构造函数初始化
public ClientreadMsg(Socket socket){
try{
this.socket=socket;
is=new BufferedReader(new InputStreamReader(
this.socket.getInputStream()));
}catch(Exception e){System.out.println(e.toString());}
}
@Override
public void run() {
// TODO Auto-generated method stub
super.run();
try{
while(true){
//读取数据
String data=is.readLine();
if(data!=null&&!data.equals("")){
//如果读取到bye则结束
if(data.equalsIgnoreCase("bye")){
is_taking=true;
break;
}
System.out.println("收到服务端信息:"+data);
}
}
}catch(Exception e){System.out.println(e.toString());}finally{try{is.close();}catch(Exception e){System.out.println(e.toString());}}
}
}
Services(服务端)
public static void main(String[] args) {
// TODO Auto-generated method stub
Socket socket = null;
PrintWriter out = null;
BufferedReader br = null;
ServerSocket server = null;
try {
// 创建一个ServerSocket在端口9086监听客户请求
server = new ServerSocket(9089);
System.out.println("服务端已经开启!!!");
// 使用accept()阻塞等待客户请求,有客户请求到来则产生一个Socket对象,并继续执行
socket = server.accept();
// 由Socket对象得到输入流,并构造相应的BufferedReader对象
//把直接流转换成字符流
out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(
socket.getOutputStream())), true);
br = new BufferedReader(new InputStreamReader(System.in));
if (socket != null) {
System.out.println("有用户上线啦:" + socket);
out.println(socket + "已经连接上服务端!");
out.flush();
}
//新建一个读取消息的线程
new readMsgThread(server, socket).start();
while (true) {
String line = br.readLine();
if (line != null) {
out.println(line);
out.flush();
System.out.println("提示:发送到客户端的消息发送成功(正在等待客户端回复,请稍候...)!");
}
}
} catch (Exception e) {
System.out.println(e.toString());
} finally {
try {
socket.close();
server.close();
} catch (Exception e) {
}
}
}
服务端中的readMsgThread类主要是为了读取客户端发来的消息模式一条线程,我们把读取和发送消息分开两条线程实现:
public class readMsgThread extends Thread {
private ServerSocket server=null;
private BufferedReader is = null;
private Socket socket = null;
public readMsgThread(ServerSocket mserver,Socket socket){
System.out.println("实例化消息读取线程!");
this.server=mserver;
this.socket=socket;
try{
is = new BufferedReader(new InputStreamReader(
this.socket.getInputStream()));
}catch(Exception e){
System.out.println(e.toString());
}
}
@Override
public void run() {
// TODO Auto-generated method stub
super.run();
try{
while(true){
String data=is.readLine();
if(data!=null&&!data.equals("")){
if(data.equalsIgnoreCase("bye")){
break;
}
System.out.println("收到客户端信息:"+data);
}
}
}catch(Exception e){
System.out.println(e.toString());
}finally{
try{is.close();}catch(Exception e){System.out.println(e.toString());}
}
}
}
总结:其实代码的逻辑过程应该比较清楚,
客户端发送消息(一条线程),客户端读取消息(一条线程);
服务端发送消息(一条线程),服务端读取消息(一条线程)
这也是多线程的简单应用。
demo地址:http://download.csdn.net/detail/leifengpeng/8540665