将不同地理区域的具有独立功能的计算机,通过通信设备与通信线路连接起来,有功能完善的软件实现信息资源共享和信息传递的系统。
java语言是支持网络的,java把网络实现细节封装成不同的类,由JVM进行控制,使用这些类开发程序就可以实现网络编程的数据传输。
直接或间接地通过网络协议与其它计算机进行通讯。
网络编程中两个主要的问题:
如何准确地找到网络中的某台主机:通过IP(找到主机)+端口号(确定是主机中的哪个程序);
如何高效可靠传输数据:只要取决于使用的通信协议(TCP和UDP)。
IP是主机的唯一标识,在Windows系统下,大开cmd,输入ipconfig命令,回车即可查看本机IP地址。本地回环地址(127.0.0.1)代表设备的本地虚拟接口。
端口号是计算机中的应用程序的一个整数数字标号,用来区分不同的应用程序。065535为有效地端口号,其中01024已被占用,所以我们要对一些程序定义端口号的时候,要选择1024 ~ 65535范围内的整数。
通信协议通信双方约定以哪种方式传输数据 。
传输控制协议TCP(Transmission Control Protocol):是一种面向连接的、可靠的、基于字节流的传输层通信协议。
在使用TCP之前是需要建立TCP连接的,形成传输数据通道,在数据通道中可以进行大量的数据传输。
传输前采用“三次握手”的方式,包含两个通信进程:客户端,服务器。
传输完数据后,需要断开连接,效率低。
断开连接时需要进行“四次挥手”。
用户数据报协议UDP(User Datagram Protocol):支持无线连接的传输协议,该协议称为用户数据报协议。
在使用UDP时将数据、源、目的封装成数据包,不需要建立传输数据通道。
每个数据包的大小限制在64k内。
因其不需要建立链接,所以是不可靠的,结束时也不需要释放资源,速度快。
客户端Socket的工作过程:
创建Socket.根据服务器的IP地址和端口号,构造Socket类对象,如果服务器有响应,就链接到服务器的通信链路。否则链接失败,出现异常。
打开连接到Socket的输入输出流.使用 getInputStream()方法获得输入流,使用getOutputStream()方法获得输出流,进行数据传输。
按照一定的协议对Socket进行读写.
关闭Socket.断开链接释放线路。
客户端
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
public class Client1 {
public static void main(String[] args) throws IOException {
//创建一个客户端Socket,在创建时就链接主机,连接不到就会报错
Socket socket = new Socket("127.0.0.1",9898);
//向服务器端发送消息 getOutputStream()返回的是OutputStream类型的数据
OutputStream out = socket.getOutputStream();
out.write("你好服务器".getBytes("UTF-8"));
//读取服务器返回的消息
InputStream in = socket.getInputStream();
byte[] bytes = new byte[1024];
int size =in.read(bytes);
String msg = new String(bytes,0,size);
System.out.println(msg);
}
}
服务器端
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(9898);
System.out.println("服务器开启,等待客户端连接!");
//监听,一旦监听到有客户端向服务器发送请求,就会获得对应客户端的Socket.
Socket socket = serverSocket.accept();
System.out.println("链接成功");
//输出客户端发送的消息
InputStream in = socket.getInputStream();
byte[] b = new byte[1024];
int size =in.read(b);
String mag = new String(b,0,size,"utf-8");
System.out.println(mag);
//服务器端向客户端发送数据
OutputStream out = socket.getOutputStream();
out.write("你好客户端,有事吗?".getBytes("utf-8"));
}
}
以上代码只能发送一次,引入循环就可以实现多次发送:
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.util.Scanner;
//客户端
public class Client {
public static void main(String[] args) throws IOException {
//创建一个Socket客户端,包含服务器的IP地址和端口号,
Socket socket = new Socket("127.0.0.1",9999);
Scanner scanner = new Scanner(System.in);
//引入DataOutputStream处理流 数据输出
DataOutputStream dout = new DataOutputStream(socket.getOutputStream());
DataInputStream din = new DataInputStream(socket.getInputStream());
while (true){
System.out.println("客户端输入:");
String msg = scanner.next();
dout.writeUTF(msg);
System.out.println("服务器端说:"+din.readUTF());
}
}
}
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
//服务器
public class Server {
public static void main(String[] args) throws IOException {
ServerSocket server = new ServerSocket(9999);
Socket socket = server.accept();
Scanner scanner = new Scanner(System.in);
System.out.println("连接上了");
DataInputStream din = new DataInputStream(socket.getInputStream());
DataOutputStream dout = new DataOutputStream(socket.getOutputStream());
while (true){
String msg = din.readUTF();
System.out.println(msg);
//服务器发送
String msg2 = scanner.next();
dout.writeUTF(msg2);
}
}
}
第二次修改后只能客户端发送一次服务器一次这样循环还达不到客户或者服务器可以一直发。
DatagramSocket 和 DatagramPacket 实现了基于UDP协议的网络程序。
DatagramSocket :发送数据
DatagramPacket对象封装了数据报,包含了数据内容,发送端的IP地址和端口号,接收端的IP地址和端口号。
UDP协议每个数据报都给出了完整的地址信息,因此无需建立发送端和接收端的链接。
发送端和接收端是两个独立的程序。发送端只管发送不会理会是否发送端接收到。
UDP编程的流程:
import java.io.IOException;
import java.net.*;
public class Client {
public static void main(String[] args) throws IOException {
//创建DatagramSocket对象方便下面发送数据报
DatagramSocket socket = new DatagramSocket();
byte[] bytes ="你好呀!".getBytes("UTF-8");
while (true){
//创建DatagramPacket包装数据报,包括数据,数据长度,地址,目标端口
DatagramPacket dp = new DatagramPacket(bytes,bytes.length, InetAddress.getByName("192.168.1.143"),9999);
//发送
socket.send(dp);
}
}
}
public class Server {
public static void main(String[] args) throws IOException {
//接收端指定监听的端口
DatagramSocket dsocket = new DatagramSocket(9999);
byte[] bytes = new byte[1024];
while (true){
//包装数据报
DatagramPacket dp = new DatagramPacket(bytes,bytes.length);
//接收
dsocket.receive(dp);
// 将接收的数据报转换为字符串 发送方发送的内容长度
String msg = new String(bytes,0, dp.getLength());
System.out.println(msg);
}
}
}