网络编程从大的方面说就是对信息的发送与接收(如,打电话,发信息),中间传输为物理线路的作用。
网络编程最主要的工作就是在发送端把信息通过规定好的协议进行打包发送,在接收端按照规定好的协议把包进行解析,从而得到发送端的信息,以此达到通信的目的。中间最主要的就是数据包的组装,数据包的过滤,数据包的捕获,数据包的分析等。
1.什么是 TCP/ IP
IP 地址分类:
- IPV4: 127.0.0.1,实际上是把32位整数按8位分组后的数字表示,站4个字节组成,目的是便于阅读。每一个字节0-255,总共42亿,而其中30亿在北美,亚洲却只有4亿。在2011年就已经用尽。
- IPV6: IPv6地址实际上是一个128位整数,它是目前使用的IPv4的升级版,2408:84f7:93:61f1:850a:ea26:e895:f314 ,并由8个无符号整数组成。
TCP 协议则是建立在 IP 协议之上的。TCP 协议负责在两台计算机之间建立可靠连接,保证数据包按顺序到达。TCP 协议会通过三次握手建立连接,然后,对每个 IP 包编号,确保对方按顺序收到,如果包丢掉了,就自动重发。
TCP 协议传输的数据包里不仅有要发送的信息,还包含了原 IP 地址和目标 IP 地址,原端口和目标端口。
网络编程中许多常用的更高级的协议都是建立在 TCP 协议基础上的,如用于浏览器的 HTTP 协议、发送邮件的 SMTP 协议等。
InetAddress 类:
InetAddress 是 ip 地址的 java 表示方式。这个类的实例也可以用在UDP DatagramSockets、普通 Socket 类和 ServerSocket 类,并且InetAddress 类提供许多其他的方法以供使用。
InetAddress 类中没有构造方法,不可以 new 对象,只能通过类名点去调用。
- getByName( String host ) 获取与 Host 相对应的 InetAddress 对象
- getHostAddress() 获取 InetAdress 对象所包含的IP地址
- getHostName() 获取此 IP 地址的主机名
- getLocalHost() 返回本地主机的 InetAddress 对象
用 getHostName() 与 getHostAddress() 方法获得本地主机的本机名,ip 地址:
import java.net.InetAddress;
import java.net.UnknownHostException;
//InetAddress是一个静态类,调用相应的方法类名点
public class TestInetAddress {
public static void main(String[] args) {
InetAddress ip;
try {
ip=InetAddress.getLocalHost();
String localname=ip.getHostName();
String locaip=ip.getHostAddress();
System.out.println("本机名:"+localname);
System.out.println("本机ip:"+locaip);
}catch(UnknownHostException e) {
e.printStackTrace();
}
}
}
2.端口
端口表示计算机上的一个程序的进程:
- 不同的进程有不同的端口号,主要是为了区分软件。故端口号不能重复。
- 一台电脑可有 0-65535 不同的端口,也就是说一台电脑可以跑 65535 个程序。
- 不同的协议可以用相同的端口。如 tcp 使用 80 端口,udp 也可使用 80 端口。( tcp:80,udp:80 )
端口分类:
- 公有端口:0-1023
- 程序注册端口:1024-49151
- 动态、私有:49152-65535
Windows 系统下可以通过以下命令查看端口和进程:
$ netstat -ano #查看所有的端口
$ netstat -ano|findstr "1056" #查询具体的端口
$ tasklist|findstr "8696" #查看指定端口的进程
用 InetAddress 类和 InetSocketAddress 类获得端口:
import java.net.InetAddress;
import java.net.InetSocketAddress;
public class InetSocketAddresss {
public static void main(String[] args) {
InetSocketAddress add=new InetSocketAddress("127.0.0.1",8080);
System.out.println(add.getHostName());
System.out.println(add.getPort());
InetAddress addr=add.getAddress();//获得端口的ip;
System.out.println(addr.getHostAddress());//返回ip;
System.out.println(addr.getHostName());//输出端口名;
}
}
3.通讯协议
重要的协议:
- TCP,用户传输协议
- UDP, 用户数据报协议
- IP,网络互联协议
TCP/IP 模型:
TCP 协议需要在客户端与服务端建立连接,比较稳定,但是需要数据传输完成才释放连接,例如打电话,效率较低。建立连接有三次握手,四次挥手过程。
UDP 协议不需要连接,客户端与服务端之间没有明确的界限,不管是否建立连接都可以传输数据给你,例如发短信,但是比较不稳定。
4.发送与接收数据
1.TCP 协议 大多数连接都是可靠的 TCP 连接。创建 TCP 连接时,主动发起连接的叫客户端,被动响应连接的叫服务端。
举个例子,当我们在打电话的时候我们要先拨通电话号码,让后对方接听,也可以挂掉。而接通过后并接听,建立连接成功过后,进行通话。同样在 TCP 协议传输数据的过程中,必须建立连接,才能传输打包数据。
客户端使用 TCP 协议 向服务器发送消息需要以下 3 步:
- 获取服务器的IP地址。
- 创建端口号。
- 建立 socket 连接等待用户连接 accept。
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
//客户端
public class TcpClientDemo01 {
public static void main(String[] args) {
Socket socket = null;
OutputStream os= null;
try {
//1.要知道服务器地址
InetAddress byName = InetAddress.getByName("127.0.0.1");
//2.端口号
int port=9999;
//3.创建一个socket连接
socket = new Socket(byName,port);
//发送消息 IO流
os= socket.getOutputStream();
os.write("tcp协议练习!".getBytes());
} catch (Exception e) {
e.printStackTrace();
}finally {
if (os !=null){
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (socket!=null){
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
服务端接收客户端发送来的数据分为以下 3 步:
- 建立服务器的端口 serverSocker。
- 等待用户连接 accept。
- 接受用的数据,并读取。
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
//服务端
public class TcpServerDemo01 {
public static void main(String[] args) {
ServerSocket serverSocker =null;
Socket socket = null;
InputStream is = null;
ByteArrayOutputStream byteArrayOutputStream = null;
try {
//1.我有一个地址
serverSocker = new ServerSocket(9999);
while (true){
//2.等待客户端连接过来
socket = serverSocker.accept();
//3.读取客户端的消息
is = socket.getInputStream();
//管道流
byteArrayOutputStream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len;
while ((len=is.read(buffer))!=-1){
byteArrayOutputStream.write(buffer,0,len);
}
System.out.println(byteArrayOutputStream.toString());
}
} catch (IOException e) {
e.printStackTrace();
}finally {
//关闭资源
if( byteArrayOutputStream !=null){
try {
byteArrayOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (is!=null){
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (socket!=null){
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if ( serverSocker!=null){
try {
serverSocker.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
需要注意的是,要先运行服务端( TcpServerDemo01 ),再运行客户端( TcpClientDemo01 ),否则会出现以下错误:
错误原因:tcp 协议必须创建连接才能发送数据。
2.UDP 协议
TCP 是建立可靠连接,从上述案例可以看出通信双方都可以以流的形式发送数据。相对 TCP,UDP 则是面向无连接的协议。
我们在使用 UDP 协议时,不需要建立 socket 连接,只需要知道对方的 IP 地址和端口号,就可以直接发数据包,但是不一定能到达目的主机。就如发短信一样,我有你的手机号,我可以随时给你发短信,但是有没有收到短信就只有你知道了。
虽然用 UDP 传输数据不太可靠,但它的优点是和 TCP 比,速度快,对于不要求可靠到达的数据,就可以使用 UDP 协议。
利用 UDP 协议向服务器发送信息:
import java.net.DatagramPacket;
import java.net.DatagramSocket;
//等待客户端的连接
public class UDPServer {
public static void main(String[] args) throws Exception {
//开放端口
DatagramSocket socket = new DatagramSocket(9908);
//接受数据包
byte[] buffer = new byte[1024];
DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length);
socket.receive(packet);//阻塞接受
System.out.println(packet.getAddress().getHostAddress());
System.out.println(new String(packet.getData(),0,packet.getLength()));
//关闭连接
socket.close();
}
}
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
//不需要连接服务器
public class UDPClient {
public static void main(String[] args) {
DatagramSocket socket = null;
try {
//1.建立一个连接 Socker
socket = new DatagramSocket();
//2.建立包
String msg = "您好,服务器!";
//发送给谁
InetAddress byName = InetAddress.getByName("127.0.0.1");
int port = 9908;
// 数据 数据的长度 发送给谁
DatagramPacket datagramPacket = new DatagramPacket(msg.getBytes(), 0, msg.getBytes().length, byName, port);
//3.发送包
socket.send(datagramPacket);
} catch (Exception e) {
e.printStackTrace();
}finally {
//4.关闭流
if (socket !=null){
socket.close();
}
}
}
}
5.总结
在本文中,我们主要了解了怎么用 Java 获取主机的 IP 、端口以及如何发送和接收数据,希望这对你的工作能有帮助。