关于网络编程的相关知识
- ip:是用来网络编程时,识别需要通信的电脑或主机
- 端口号:在获取主机ip后,指定需要进行数据交流的APP
- 客户端:用来向服务器发送数据或请求的电脑或主机
- 服务器端:用来接受客户端发送的数据或请求
- UDP编程的特点:客户端与服务器端之间不需要确保已正确的连接,客户端只需要发送数据,而不保证服务器端能够正确的接收到客户端发送的数据。发送的数据都是以数据包的形式一个包一个包的发送,缺点就是不能够发送较大的数据
- TCP编程特点:客户端与服务器端之间进行通信前必须保证已经建立正确的连接,数据之间的通信是通过管道(数据流)进行交互的,只要管道没有关闭,就可以一直进行数据的交流传递
一、 UDP网络编程
- 发送端(客户端):
DatagramSocket ------> java.net.DatagramSocket ------> 创建socket
DatagramPacket ------> java.net.DatagramPacket ------> 创建数据包
InetAddress ------> java.net.InetAddress ------> 封装ip - 示例
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Scanner;
public class Udp_send_thread extends Thread{//创建线程类
private int port;
private String ip;
public Udp_send_thread(int port, String ip) {
this.port = port;
this.ip = ip;
}
public void run() {
DatagramSocket socket = null;
try {
socket = new DatagramSocket();//socket的创建,不需要指定端口
} catch (SocketException e) {
System.out.println("创建socket失败");
}
InetAddress address = null;
try {
address = InetAddress.getByName(ip);//ip的封装
} catch (UnknownHostException e) {
e.printStackTrace();
}
Scanner input = new Scanner(System.in);//控制台输入
while(true) {
String str = input.nextLine();
DatagramPacket p = new DatagramPacket(str.getBytes(), str.length(), address, port);//数据包的封装
try {
socket.send(p);//数据包的发送
} catch (IOException e) {
e.printStackTrace();
}
if(str.equals("end")) {//输入end退出发送,结束线程
break;
}
}
if(socket != null) {//socket的关闭
socket.close();
}
}
}
- 接收端(服务器端):
DatagramSocket ------> java.net.DatagramSocket ------> 创建socket
DatagramPacket ------> java.net.DatagramPacket ------> 创建数据包 - 示例
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
public class Udp_receive_thread extends Thread{//创建线程类
private int port;
public Udp_receive_thread(int port) {
this.port = port;
}
public void run() {
DatagramSocket socket = null;
try {
socket = new DatagramSocket(port);//创建socket,指定端口号
} catch (SocketException e) {
System.out.println("创建socket失败");
}
byte[] buf = new byte[1024];//接收数据的buf
while(true) {
DatagramPacket p = new DatagramPacket(buf, buf.length);//创建数据包
try {
socket.receive(p);//接收数据
} catch (IOException e) {
e.printStackTrace();
}
String str = new String(p.getData(), 0, p.getLength());
System.out.println(port + ":" + str);
if(str.equals("end"))//输入end退出接收,结束线程
break;
}
if(socket != null) {//socket的关闭
socket.close();
}
}
}
- 接收端与发送端的不同
① 发送端创建socket不需要指定端口号,接收端需要指定
② 发送端创建数据包需要指定端口号和ip地址(用InetAddress类进行封装),接收端只需要传递接收数据的缓存及长度
③ 发送端发送数据用send()函数,接收端接收数据用receive()函数,接收到的数据用getData()进行获取,长度用getLength()获取
④ 退出编程时,需要关闭socket - 网络编程线程的调用
//利用线程相互通信
public class DCP_Main_Send1 {
public static void main(String[] args) {
new Udp_send_thread(12345, "127.0.0.1").start();
new Udp_receive_thread(12346).start();
}
}
public class DCP_Main_Send2 {
public static void main(String[] args) {
new Udp_receive_thread(12345).start();;
new Udp_send_thread(12346, "127.0.0.1").start();
}
}
二、 TCP网络编程
- 发送端(客户端):
Socket ------> java.net.Socket ------> 创建socket
OutputStream ------> java.io.OutputStream ------> 创建输入流 - 示例
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
public class TcpSend {
public static void main(String[] args){
Socket socket = null;
try {
socket = new Socket("127.0.0.1", 12345);//创建socket
OutputStream output = socket.getOutputStream();//获取输入流
output.write("我是中国人,我很骄傲".getBytes());//发送数据
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
try {
if(socket != null)
socket.close();//关闭socket
} catch (IOException e) {
e.printStackTrace();
}
}
}
- 接收端(服务器端):
Socket ------> java.net.Socket ------> 创建socket
ServerSocket ------> java.net.ServerSocket ------> 创建serverSocket
InputStream ------> java.io.InputStream ------> 创建输出流 - 示例
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class TcpReceiva {
public static void main(String[] args){
ServerSocket serverSocket = null;
Socket socket = null;
try {
serverSocket = new ServerSocket(12345);//创建serverSocket
socket = serverSocket.accept();//等待绑定客户端socket
InputStream input = socket.getInputStream();//获取输出流
byte[] buf = new byte[1024];
int length = input.read(buf);//获取数据
String str = new String(buf,0,length);
System.out.println(str);
} catch (IOException e) {
e.printStackTrace();
}
try {
if(socket != null)
socket.close();//关闭客户端socket
} catch (IOException e) {
e.printStackTrace();
}
try {
if(serverSocket != null)
serverSocket.close();//关闭serverSocket
} catch (IOException e) {
e.printStackTrace();
}
}
}
- 发送端与接收端的差异
① 发送端使用Socket,接收端使用ServerSocket
② 接收端创建ServerSocket后需要通过accept()函数获取客户端的socket
③ 发送端使用write()函数发送数据,接收端使用read()函数接收数据
④ 发送端使用OutputStream流,接收端使用InputStream流
⑤ 发送端创建Socket需要传ip和端口号,接收端创建ServerSocket只需要传端口号