----------- android培训、java培训、java学习型技术博客、期待与您交流! ------------
对于网络编程,首先我们需要知道的是,网络的通讯(数据交互)的原理:
比如,两台电脑直接进行信息交互:
1.首先要知道对方的IP地址或者主机名称,简单来说就是:要知道它在那里?
2.数据发送到对方指定的应用程序上(比如:QQ、msn两个程序,你到底要发给谁?所以需要指定),为了标识这些应用程序,所以给这些网络应用程序都使用数字进行标识,为了方便称呼这个数字,称之为端口,这个是指的逻辑端口。简单来说就是:要知道发给谁?
3. 知道了需要和那个应用程序进行信息交互,而在通讯过程中,定义了对应的通讯规则,称之为协议。国际组织定义的通用协议是ICP/IP。简单来说就是:我们直接使用什么交流规则,比如:使用手语或者口语。
说了这么多,那么网络编程的目的是什么?
就是指直接或间接地通过网络协议与其他计算机进行通信。
那么根据上面的信息,我们可以知道网络通讯的要素有:
1. IP地址:ip地址是数字型的,用来标识网络中的某个设备,其中:IPV4是32位,IPV6是128位
2. 端口号:端口是一个16位的整数,用于表示数据提交给那个通信程序处理。因此,端口就是应用程序与外界交流的出入口,所以同一台机器上不能有两个程序使用同一个端口,有效端口:0~65535 ,其中0~1024是系统使用或者保留端口。
3. 传输协议:通讯之间的规则,常见协议是:TCP/UDP
而对应网络通讯,我们按照通讯层次,定出了对应的网络模型:
1.OSI参考模型:
分为:应用层,表示层,会话层,传输层,网络层,数据链接层和物理层
2.TCP/IP参考模型
分为:
应用层:包含了OSI参考模型的应用层,表示层,会话层, 这层中常见HTTP/FTP协议
传输层:这层中常见TCP/UDP协议
网际层:这层中常见IP协议
主机至网络层:包含了OSI参考模型的数据链接层和物理层
如何获取对应的IP信息,,在Java中,提供了InetAdress类。
创建InetAdress的实例方式:
注:InetAddress类没有提供构造函数
1.getByName(String host):根据主机获取对应的InetAddress对象。
2.getByAddress(byte[] addr):根据原始IP地址来获取对应的InetAddress对象。
InetAdress提供获取对应的IP地址和主机名的方法:
1.String getCannonicalHostName():获取此IP地址的全限定域名。
2.String getHostAddress():返回该InetAddress实例对应的IP地址字符串。
3.String getHostName():获取此IP地址的主机名。
实例:
import java.net.*;
publicclass IPDemo{
publicstaticvoid main(String[] args) throws Exception
{
//获取本地IP信息
InetAddress i = InetAddress.getLocalHost();
System.out.println(i.toString());
System.out.println("address:"+i.getHostAddress());
System.out.println("name:"+i.getHostName());
//根据主机名获取InetAddress实例
InetAddress ia_baidu = InetAddress.getByName("www.baidu.com");
System.out.println("InetAddress:" + ia_baidu.getHostAddress());
//根据IP地址获取InetAddress实例
InetAddress ia_1 = InetAddress.getByAddress(newbyte[] {127, 0, 0, 1});
System.out.println(ia_1.getCanonicalHostName());
}
}
那么对于网络通讯协议,常见的有:
TCP:是一种面向连接的保证可靠传输的协议。通过TCP协议传输,得到的是一个顺序的无差错的数据流。发送方和接收方各有一个socket,两个socket之间必须建立连接,以便在TCP协议的基础上进行通信,当一个socket(通常都是server socket)等待建立连接时,另一个socket(client socket)可以要求进行连接,一旦这两个socket连接起来,它们就可以进行双向数据传输,双方都可以进行发送或接收操作,这个过程类似于生活中的打电话。
UDP:是一种无连接的协议,也不进行差错及流量的控制。因此UDP提供的服务是不可靠的,基于UDP的应用程序可根据情况自己承担可靠性方面的工作。
TCP/UDP区别:
UDP:
将数据及源和目的封装成数据包中,不需要建立连接.
每个数据包的大小限制在64K以内,
因无连接,是不可靠协议.
不需要建立连接,速度快
TCP:
建立连接,形成传输数据的通道.
在连接中进行大数据量传输,通过三次握手完成连接,是可靠协议.
必须建立连接,效率会稍低
上面需要注意的是:
三次握手连接什么意思?
比如两个人进行问候。
甲:你吃了么? 相当于第一次握手,发送一个请求。
乙:我吃了! 相当于第二次握手,接受请求,并且进行应答,并且返回一个状态
甲:呃,我知道了。 相当于第三次握手,接受返回状态。
那么在Java中,TCP/UDP是怎么进行实现的呢?
一,UDP
由于是通讯过程,那么就会分为发送端和接收端
(1)、发送端
要求:通过udp传输方式,将一段文字数据发送出去
步骤:
1.建立udpsocket服务
2.提供数据,将数据封装到数据包中
3.通过socket服务的发送功能,将数据包发出去
4.关闭资源
例如:
publicstaticvoid udpSend () throws Exception {
DatagramSocket ds = new DatagramSocket();// 创建了udp的Socket服务
byte[] arr = "Udp message come to!".getBytes();// 创建数据源
// 建立数据抱包对象,并确认发送数据,长度.以及发送源,以及端口.
DatagramPacket dp = new DatagramPacket(arr, arr.length, InetAddress.getByName("192.168.241.1"), 4000);
ds.send(dp);// 发送数据
ds.close();// 关闭socket服务
}
(2)、接收端
要求:定义一个应用程序,用于接收udp协议传输的数据并处理
步骤:
1. 定义udpsocket服务。通常会监听一个端口。其实就是给这个接收网络应用程序定义数字标识。方便于明确哪些数据过来该应用程序可以处理
2.定义一个数据包,因为要存储接收到的字节数据。数据包对象中提供了可以提取字节数据中不同数据信息的功能
3.通过socket服务的receive方法将接收到的数据存入已定义好的数据包中
4.通过数据包对象的特有功能,将不同的数据取出,打印在控制台上
5.关闭资源
例如:
publicstaticvoid udpGet() throws Exception {
//创建socket服务,并定义固定端口
DatagramSocket ds = new DatagramSocket(4000);
byte[] arr = newbyte[1024];
DatagramPacket dp = new DatagramPacket(arr, arr.length);
ds.receive(dp);
//获取数据
String data = new String(dp.getData(), 0, dp.getLength());
//获取ip
String ip = dp.getAddress().getHostAddress();
//获取端口号
int port = dp.getPort();
System.out.println(ip+":"+data+":"+port);
ds.close();
}
小技巧:
要是一直开着接收发送端发送数据,那么可以通过使用循环方法,一直接收数据。
拓展,小程序模拟聊天程序
/*
有收数据的部分,和发数据的部分。
这两部分需要同时执行。
那就需要用到多线程技术。
一个线程控制收,一个线程控制发。
因为收和发动作是不一致的,所以要定义两个run方法。
而且这两个方法要封装到不同的类中。
*/
import java.io.*;
import java.net.*;
class Send implements Runnable
{
private DatagramSocket ds;
public Send(DatagramSocket ds)
{
this.ds = ds;
}
publicvoid run()
{
try
{
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
String line = null;
while((line=bufr.readLine())!=null)
{
byte[] buf = line.getBytes();
DatagramPacket dp = new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.1.103"),10023);
ds.send(dp);
if("886".equals(line))
break;
}
}
catch (Exception e){
thrownew RuntimeException("发送端失败");
}
}
}
class Rece implements Runnable{
private DatagramSocket ds;
public Rece(DatagramSocket ds){
this.ds = ds;
}
publicvoid run()
{
try
{
while(true)
{
byte[] buf = newbyte[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());
if("886".equals(data)){
System.out.println(ip+"....离开聊天室");
break;
}
System.out.println(ip+":"+data);
}
}
catch (Exception e)
{
thrownew RuntimeException("接收端失败");
}
}
}
class ChatDemo{
publicstaticvoid main(String[] args) throws Exception
{
DatagramSocket sendSocket = new DatagramSocket();
DatagramSocket receSocket = new DatagramSocket(10023);
new Thread(new Send(sendSocket)).start();
new Thread(new Rece(receSocket)).start();
}
}
二,TCP
TCP传输数据,分为客户端和服务端
客户端对应的对象是Socket
服务端对应的对象是ServerSocket
建立连接后,通过Socket中的IO流进行数据的传输.最后关闭socket客户端.
关闭服务端是可选操作
(1)、客户端
需求:给服务端发送给一个文本数据。
步骤:
1.创建Socket服务。并指定要连接的主机和端口。
2.建立连接成功后,通过Socket中的IO流进行数据传输
例如:
import java.io.*;
import java.net.*;
class TcpClient{
publicstaticvoid main(String[] args) throws Exception
{
//创建客户端的socket服务。指定目的主机和端口
Socket s = new Socket("192.168.1.103",10034);
//为了发送数据,应该获取socket流中的输出流。
OutputStream out = s.getOutputStream();
out.write("tcp,hello!".getBytes());
s.close();
}
}
(2)、服务端
需求:定义端点接收数据并打印在控制台上。
步骤:
1,建立服务端的socket服务。ServerSocket();
并监听一个端口。
2,获取连接过来的客户端对象。
通过ServerSokcet的 accept方法。没有连接就会等,所以这个方法阻塞式的。
3,客户端如果发过来数据,那么服务端要使用对应的客户端对象,并获取到该客户端对象的读取流来读取发过来的数据。
并打印在控制台。
4,关闭服务端。(可选)
例如:
class TcpServer{
publicstaticvoid main(String[] args) throws Exception{
//建立服务端socket服务。并监听一个端口。
ServerSocket ss = new ServerSocket(10034);
//通过accept方法获取连接过来的客户端对象。
while(true){
Socket s = ss.accept();
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip+".....connected");
//获取客户端发送过来的数据,那么要使用客户端对象的读取流来读取数据。
InputStream in = s.getInputStream();
byte[] buf = newbyte[1024];
int len = in.read(buf);
System.out.println(new String(buf,0,len));
s.close();//关闭客户端.
}
//ss.close();
}
}
拓展,小程序演示tcp的传输的客户端和服务端的互访
import java.io.*;
import java.net.*;
/*
演示tcp的传输的客户端和服务端的互访。
需求:客户端给服务端发送数据,服务端收到后,给客户端反馈信息。
*/
/*
客户端:
1,建立socket服务。指定要连接主机和端口。
2,获取socket流中的输出流。将数据写到该流中。通过网络发送给服务端。
3,获取socket流中的输入流,将服务端反馈的数据获取到,并打印。
4,关闭客户端资源。
*/
class TcpClient2{
publicstaticvoid main(String[] args)throws Exception{
Socket s = new Socket("192.168.1.254",10004);
OutputStream out = s.getOutputStream();
out.write("服务端,你好".getBytes());
InputStream in = s.getInputStream();
byte[] buf = newbyte[1024];
int len = in.read(buf);
System.out.println(new String(buf,0,len));
s.close();
}
}
class TcpServer2{
publicstaticvoid main(String[] args) throws Exception{
ServerSocket ss = new ServerSocket(10004);
Socket s = ss.accept();
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip+"....connected");
InputStream in = s.getInputStream();
byte[] buf = newbyte[1024];
int len = in.read(buf);
System.out.println(new String(buf,0,len));
OutputStream out = s.getOutputStream();
Thread.sleep(10000);
out.write("哥们收到,你也好".getBytes());
s.close();
ss.close();
}
}