用来标识计算机上的网络应用程序,端口是一个虚拟的概念,是16位二进制正整数,故取值为0-65535(十进制)。端口一共可以在一台计算机上存在12w+(2^17)个,因为端口属于传输层,传输层有两个重要协议(TCP和UDP),所以两边各65536个(2^16)。一般来说端口够用,因为计算机上用不到12w多个网络应用。
端口0-1023为知名端口,也叫公认端口,端口1023-49151为注册端口, 比如3306(MySQL),8080(Tomcat),端口49152-65535为动态端口或者私有端口。
netstat -ano
IP地址是网络中设备的唯一标识,IP地址分为两大类
常用DOS命令
ipconfig:查看本机IP地址
ping IP地址:检查网络是否连通
示例:
特殊IP地址
子网掩码(subnet mask)又叫网络掩码、地址掩码、子网络遮罩,它是一种用来指明一个IP地址的哪些位标识的是主机所在的子网,以及哪些位标识的是主机的位掩码。子网掩码不能单独存在,它必须结合IP地址一起使用。子网掩码只有一个作用,就是将某个IP地址划分成网络地址和主机地址两部分。
Socket编程是在TCP/IP上的网络编程,Java的网络编程主要涉及到的内容是Socket编程。Socket,套接字,就是两台主机之间逻辑连接的端点。TCP/IP协议是传输层协议,主要解决数据如何在网络中传输,而HTTP是应用层协议,主要解决如何包装数据。Socket是通信的基石,是支持TCP/IP协议的网络通信的基本操作单元。它是网络通信过程中端点的抽象表示,包含进行网络通信必须的五种信息:连接使用的协议、本地主机的IP地址、本地进程的协议端口、远程主机的IP地址、远程进程的协议端口。
Socket,实际上是对TCP/IP协议的封装,Socket本身并不是协议,而是一个调用接口(API),通过Socket,我们才能使用TCP/IP协议。
示例:下面是一个客户端和服务器端进行数据交互的简单例子,客户端输入正方形的边长,服务器端接收到后计算面积并返回给客户端,通过这个例子可以初步对Socket编程有个把握。
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class TestSockeServer {
public static void main(String[] args) {
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(8080);
while (true) {
System.out.println("服务器开始运行了,等待客户端连接上来");
Socket socket = serverSocket.accept();
System.out.println(socket.getInetAddress().getHostName());
System.out.println(socket.getLocalAddress());
System.out.println(socket.getLocalPort());
// 推送一条消息过去
String msg = "欢迎您进入我们的QQ";
OutputStream os = socket.getOutputStream();
PrintWriter out = new PrintWriter(os, true);
out.println(msg);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
客户端
import java.io.*;
import java.net.InetSocketAddress;
import java.net.Socket;
public class TestSocket {
public static final String DES_IP = "127.0.0.1";
public static final int DES_PORT = 8080;
public static void main(String[] args) {
Socket socket = new Socket();
try {
socket.connect(new InetSocketAddress(DES_IP, DES_PORT));
System.out.println("成功连接到服务器");
InputStream is = socket.getInputStream();
String msg = null;
BufferedReader br = new BufferedReader(new InputStreamReader(is));
while ((msg = br.readLine()) != null ) {
System.out.println("接受到服务器端传递过来的数据,数据是:"+ msg);
}
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
out.println("我是一个客户端,我上来了,服务器,你好着吗?");
out.println("第二条数据");
} catch (IOException e) {
e.printStackTrace();
}
}
}
效果:
服务器开始运行了,等待客户端连接上来
127.0.0.1
/127.0.0.1
8080
成功连接到服务器
接受到服务器端传递过来的数据,数据是:欢迎您进入我们的QQ
Tcp是面向连接的,udp是无连接的;
Tcp是可靠的,udp是不可靠的;
Tcp只支持点对点通信,udp支持一对一,一对多,多对多的通信模式;
Tcp是面向字节流的,udp是面向报文的;
Tcp有拥塞控制机制;udp没有拥塞控制,适合媒体通信;
Tcp首部开销(20个字节)比udp的首部开销(8个字节)要大;
代码示例:
服务器端
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketException;
import java.util.Scanner;
public class TestUDPSever {
public static final String DES_IP = "127.0.0.1";
public static final int DES_PORT = 9999;
public static void main(String[] args) {
DatagramSocket socket = null;
Scanner sc = null;
try {
socket = new DatagramSocket(8888);
// 启动一个接收到线程,来进行数据接受
UDPRreceiveMsg02 udpRreceiveMsg = new UDPRreceiveMsg02(socket);
udpRreceiveMsg.start();
sc = new Scanner(System.in);
while (true) {
System.out.print(">");
String msg = sc.nextLine();
byte[] buf = msg.getBytes();
InetSocketAddress address = new InetSocketAddress(DES_IP, DES_PORT);
DatagramPacket pd = new DatagramPacket(buf, 0, buf.length, address);
socket.send(pd);
}
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
socket.close();
}
}
}
class UDPRreceiveMsg02 extends Thread {
private DatagramSocket socket;
public UDPRreceiveMsg02(DatagramSocket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
receiveMsg();
} catch (IOException e) {
e.printStackTrace();
}
}
private void receiveMsg() throws IOException {
while (true) {
byte[] buf = new byte[1024];
DatagramPacket pd = new DatagramPacket(buf, 0, buf.length);
// 等待接受数据
socket.receive(pd);
// 将数据转换出来
byte[] msg = pd.getData();
String sendIP = pd.getAddress().getHostAddress();
int sendPort = pd.getPort();
System.out.println("接受到" + sendIP + ":" + sendPort + "发送过来的数据,数据是:" + new String(msg));
}
}
}
客户端
import java.io.IOException;
import java.net.*;
public class TestUDP {
public static void main(String[] args) {
DatagramSocket datagramSocket = null;
try {
// 注意,创建一个udp socket对象,默认占据了8080
datagramSocket = new DatagramSocket(8080);
String msg = "你好啊,socket对象";
byte[] bytes = msg.getBytes();
// 数据报对象
DatagramPacket packet = new DatagramPacket(bytes, 0, bytes.length, new InetSocketAddress("127.0.0.1", 8888));
// 发送数据
datagramSocket.send(packet);
System.out.println("数据已经成功发送");
} catch (IOException e) {
e.printStackTrace();
} finally {
datagramSocket.close();
}
}
}
特点:传输数据安全,可靠,面向连接的,点对点,长连接,效率相对较低
TCP/IP 模型。一组用于实现网络互连的通信协议,将协议分成四个层次。应用层、传输层、网络层、网络接口层。
TCP,Transmission Control Protocol,传输控制协议。是一种面向连接的、可靠的、基于字节流的传输层通信协议。数据大小无限制。建立连接的过程需要三次握手,断开连接的过程需要四次挥手。
UDP,User Datagram Protocol,用户数据报协议。是一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务,每个包的大小64KB。
IP协议,Internet Protocol Address,互联网协议地址/网际协议地址。分配给互联网设备的数字标签(唯一标识)。IP地址分为两种。IPV4,分成4段8位的二进制数;IPV6,分成8段十六进制数。
Port,端口号。在通信实体上进行网络通讯的程序的唯一标识。
public class Test {
public static void main(String[] args) throws UnknownHostException {
// 获得本地主机地址对象
System.out.println(InetAddress.getLocalHost());
// 根据主机名称获得地址对象
System.out.println(InetAddress.getByName("baidu.com"));
// 获得所有相关地址对象
InetAddress[] all = InetAddress.getAllByName("baidu.com");
for (InetAddress inetAddress : all) {
System.out.println(inetAddress);
}
for (InetAddress inetAddress : all) {
System.out.println("获取IP地址字符串 " + inetAddress.getHostAddress());
// 获得IP地址主机名
System.out.println("获取IP地址主机名 " + inetAddress.getHostName());
}
}
}
结果:
KING-wjh/192.168.56.1
baidu.com/39.156.66.10
baidu.com/39.156.66.10
baidu.com/110.242.68.66
获取IP地址字符串 39.156.66.10
获取IP地址主机名 baidu.com
获取IP地址字符串 110.242.68.66
获取IP地址主机名 baidu.com
public class PublicMethod {
public PublicMethod() {
}
public static void closeAll(Closeable... hh) {
for (Closeable closeable : hh) {
if (closeable != null) {
try {
closeable.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
// 服务端
public class TestServer {
public TestServer() {
}
public static void main(String[] args) throws IOException {
ServerSocket ssocket = new ServerSocket(9527);
// 与客户端建立连接
Socket socket = ssocket.accept();
System.out.println("等待客户端输入");
InputStream ins = socket.getInputStream();
byte[] bt = new byte[1024];
// 接收客户端发来的数据
int len = ins.read(bt); // 阻塞,接收到数据才往下走
System.out.println(new String(bt, 0, len));
OutputStream ous = socket.getOutputStream();
// 向客户端发送数据
ous.write("不在。".getBytes());
PublicMethod.closeAll(ous, ins, socket, ssocket);
}
}
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
// 客户端
public class TestClient {
public TestClient() {
}
public static void main(String[] args) throws UnknownHostException, IOException {
// 本地 ip 用来测试
Socket socket = new Socket("127.0.0.1", 9527);
System.out.println("客户端已连接");
OutputStream os = socket.getOutputStream();
// 向服务端发送数据
os.write("在吗?".getBytes());
InputStream ins = socket.getInputStream();
byte[] bt = new byte[1024];
// 接收服务端发来的数据
int len = ins.read(bt); // 阻塞,接收到数据才往下走
System.out.println(new String(bt, 0, len));
PublicMethod.closeAll(ins, os, socket);
}
}
效果显示: