您的位置:首页 > 理论基础 > 计算机网络

Java网络编程基础之Scoket通信

2015-03-27 23:36 375 查看
在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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐