------ >Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
Java语言是第一个完全融入网络的语言,Java语言之所以适合编写网络应用程序有诸多有点。所有连入Internet的终端设备(包括计算机、PDA、打印机以及其他的电子设备)都有一个唯一的索引,这个索引被称为IP地址。现在Internet上的IP地址大多由四个字节组成,这种IP地址叫做IPv4。除了这种由四个字节组成的IP,在Internet上还存在一种IP,这种IP由16个字节组成,叫做IPv6。IPv4和IPv6后面的数字是Internet协议(Internet Protocol,IP)的版本号。
网络通信需要三个基本条件:
1. 找到对方IP;
2. 数据要发送到对方指定的应用程序上,为了标识这些应用程序,所以给这些网络应用程序都用数字进行标识,为了方便称呼这个数字,叫做端口或者叫逻辑端口。端口范围0~65536,通常0~1024被系统使用或保留。
3. 定义通信规则,这个规则称为协议。国际组织定义了通用协议 TCP/IP,常用的协议还有UDP。
数据在ISO七层模型中的传输过程其实是数据的封包和拆包过程。
InetAddress类是Java中用于描述IP地址的类。它在java.net包中。InetAddress没有public的构造方法,因此,要想创建InetAddress对象,必须得依靠它的四个静态方法。InetAddress可以通过getLocalHost方法得到本机的InetAddress对象,也可以通过getByName、getAllByName和getByAddress得到远程主机的InetAddress对象。
使用getLocalHost可以得到描述本机IP的InetAddress对象。getByName方法是InetAddress类最常用的方法。它可以通过指定域名从DNS中得到相应的IP地址。getByName一个String类型参数,可以通过这个参数指定远程主机的域名。
使用getAllByName方法可以从DNS上得到域名对应的所有的IP。这个方法返回一个InetAddress类型的数组。
getByAddress方法必须通过IP地址来创建InetAddress对象,而且IP地址必须是byte数组形式。
演示代码如下:
import java.net.*;
class IPDemo
{
public static void main(String[] args) throws Exception
{
//InetAddress i =InetAddress.getLocalHost(); //获取本机地址
//System.out.println(i.toString());
InetAddress ia= InetAddress.getByName("www.baidu.com"); //获取百度的主机地址和主机名
System.out.println("address:"+ia.getHostAddress());
System.out.println("name:"+ia.getHostName());
}
} 网络应用分为客户端和服务端两部分,而Socket类是负责处理客户端通信的Java类。通过这个类可以连接到指定IP或域名的服务器上,并且可以和服务器互相发送和接受数据。一般网络客户端程序在连接服务程序时要进行以下三步操作:
网络通信中常用的两种协议有TCP和UDP协议,二者区别如下:
UDP:面向无连接,将数据及源和目的封装在数据包中,发数据前无需建立连接,每个数据包大小限制在64k内。因无连接,是不可靠协议,无需建立连接,速度快。聊天,视频会议,都使用的是UDP协议。
TCP :建立连接,形成数据传输通道,在连接过程中进行大数据量传输,通过三次握手完成传输(在吗?在,我知道你在了),是可靠协议,必须建立连接,效率稍低。下载使用的是TCP协议。
下面是一个小练习,需求:动过UDP传输方式,将一段文字数据发送出去。
思路:1.建立UDPsocket服务;
2.提供数据,并将数据封装到数据包中
3.通过socket服务的发送功能,将数据包发送出去
4.关闭资源。代码实现如下:
import java.net.*;
class UDPSend
{
public static void main(String[] args) throws Exception
{
DatagramSocket ds = new DatagramSocket(); //创建UDP服务
//确定数据,并封装成数据包 DatagramPacket(byte[] buf,int length,InetAddress address,int port)
byte[] buf= "udp laile".getBytes();
DatagramPacket dp = new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.1.101"),10000);
ds.send(dp); // 发送数据包
ds.close();
}
}
class UDPRece
{
public static void main(String[] args) throws Exception
{
DatagramSocket ds = new DatagramSocket(10000); //创建udpsocket 建立端点
//定义数据包,用于存储数据
byte[] buf = new byte[1024];
DatagramPacket dp = new DatagramPacket(buf,buf.length);
//通过服务的receive方法将收到的数据存入数据包中
ds.receive(dp); //阻塞式方法,没数据就等
//通过数据包的方法获取其中的数据
String ip = dp.getAddress().getHostAddress();
String data = new String(dp.getData(),0,dp.getLength());
int port = dp.getPort();
System.out.println(ip+"::"+data+"::"+port);
//ds.close(); //关闭资源
}
}练习:编写聊天程序,
分析:有收数据和发数据部分,需要两个线程,分别负责收和发,因为收和发动作不一致,所以要定义两个run方法,而且这两个方法要封装到不同的类当中。
import java.net.*;
import java.io.*;
class Send implements Runnable
{
private DatagramSocket ds;
public Send(DatagramSocket ds)
{
this.ds=ds;
}
public void run()
{
try
{
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in) );
String line = null;
while ((line = bufr.readLine())!=null)
{
if("886".equals(line)) //如果发送886,聊天程序结束
break;
byte[] buf= line.getBytes();
DatagramPacket dp=
new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.1.101"),10002);
ds.send(dp);
}
}
catch(Exception e)
{
throw new RuntimeException("发送端失败");
}
}
}
class Rece implements Runnable
{
private DatagramSocket ds;
public Rece(DatagramSocket ds)
{
this.ds=ds;
}
public void run()
{
try
{
while (true) //循环接收
{
byte[] buf = new byte[1024]; //将数据接收到数据包中
DatagramPacket dp = new DatagramPacket(buf,buf.length);
ds.receive(dp);
String ip = dp.getAddress().getHostAddress();
String data=new String(dp.getData(),0,dp.getLength());
System.out.println(ip+"::"+data);
}
}
catch (Exception e)
{
throw new RuntimeException("接收端失败");
}
}
}
class ChatDemo
{
public static void main(String[] args) throws Exception
{
DatagramSocket sendSocket= new DatagramSocket();
DatagramSocket receSocket= new DatagramSocket(10002);
new Thread(new Send(sendSocket)).start();
new Thread(new Rece(receSocket)).start();
}
}
需求:给服务端发送一个文本数据
步骤 1.创建socket对象,指定要连接的主机和端口;
2.发送数据。实现代码如下:
import java.io.*;
import java.net.*;
class TCPClient
{
public static void main(String[] args) throws Exception
{
//创建服务端socket对象,指定要连接的主机和端口
Socket s=new Socket("192.168.1.101",10003);
//为了发送数据,获取socket流中的输出流
OutputStream out=s.getOutputStream();
out.write("TCP 数据来了 ".getBytes());
s.close();
}
}
class TCPServer
{
public static void main(String[] args) throws Exception
{
ServerSocket ss=new ServerSocket(10003); //1.
//通过acept方法获取连接过来的客户端对象
Socket s=ss.accept();
String ip=s.getInetAddress().getHostAddress();
System.out.println(ip+"......connected");
//获取客户端发送过来的数据,使用客户端对象的读取流来读取数据
InputStream in=s.getInputStream();
byte[] buf=new byte[1024];
int len = in.read(buf);
System.out.println(new String(buf,0,len));
s.close();//关闭客户端
ss.close();
}
}
需求:建立一个文本转换服务器,客户端给服务端发送文本,服务端将文本转成大写再返回给客户端。而且客户端可以不断的进行文本转换,客户端输入over时,转换结束。
分析:
客户端:既然操作的是设备上的数据,就可以使用IO技术,并按照IO的操作规律思考。
源:键盘录入。 目的:网络设备,网络输出流,操作的是文本数据,可选字符流。
步骤:
1.建立服务; 2.获取键盘录入;3.将数据发送给服务端;4.去服务端返回大写数据;5.结束,关资源。都是文本数据,可以使用字符流操作,同时提高效率,加入缓冲。
实现代码:
import java.io.*;
import java.net.*;
class TransClient
{
public static void main(String[] args) throws Exception
{
Socket s=new Socket("192.168.1.101",10005);
//定义读取键盘数据的流对象
BufferedReader bufr =new BufferedReader(new InputStreamReader(System.in));//源
//定义目的,将数据写入到Socket输出流,发给服务端
BufferedWriter bufOut=new BufferedWriter(new OutputStreamWriter(s.getOutputStream())); //目的
//定义一个socket读取流,读取服务器返回的大写信息
BufferedReader bufIn=
new BufferedReader(new InputStreamReader(s.getInputStream()));
String line=null;
while ((line =bufr.readLine())!=null)
{
if ("over".equals(line))
break;
bufOut.write(line);
bufOut.newLine(); //换行符,结束标记
bufOut.flush();
String str=bufIn.readLine();
System.out.println("Server::"+ str);
}
bufr.close();
s.close();
}
}
class TransServer
{
public static void main(String[] args) throws Exception
{
ServerSocket ss=new ServerSocket(10005);
Socket s =ss.accept();
String ip= s.getInetAddress().getHostAddress();
System.out.println(ip+"...connected");
//读取socket读取流中的数据
BufferedReader bufIn=
new BufferedReader(new InputStreamReader(s.getInputStream()));
//目的,socket输出流,将大写数据写入到socket输出流,并发送给客户端
BufferedWriter bufOut=
new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
String line=null;
while ((line =bufIn.readLine())!=null)
{
System.out.println(line);
bufOut.write(line.toUpperCase());
bufOut.newLine(); //换行符,结束标记
bufOut.flush();
}
s.close();
ss.close();
}
}原因:客户端和服务端都有阻塞式方法,这些方法没有读到结束标记就一直等待。解决方法:添加换行符,作为结束标记。
原文地址:http://blog.csdn.net/hpu186/article/details/45481453