网络编程
您的导航
- 网络编程
- 网络编程基础知识
- 一、网络编程三要素
-
- 二、IP地址与InetAddress类
- IP地址分类
- InetAddress类
- 三、端口(Port)与 InetSocketAddress
- InetSocketAddress
- 四、通信协议
-
- TCP
-
- UDP
- 一、UDP消息发送
-
- 二、UDP实现聊天
-
- 三、多线程UDP聊天程序
-
网络编程基础知识
一、网络编程三要素
-
IP地址
-
端口
-
协议
通信:TCP、UDP协议。(传输层)
IP地址
- 是网络中设备的唯一标识
- 分为两大类
- IPv4
- IPv6
端口
-
是设备上应用程序的唯一标识。
-
端口号:用两个字节表示整数,它的取值范围是0~65535。其中,周知端口: 0~1023之间的端口用于一些知名的网络服务和应用。
注册端口: 普通的应用程序需要使用1024~49151的端口号。如果端口号被另外一个服务或应用所占用,会导致当前程序启动失败。
**动态端口:**49152~65535,之所以称为动态端口,是因为它一般不固定分配某种进程,而是动态分配。
协议
- 计算机网络中,连接和通信的规则被称为网络通信协议
- 传输层的两种协议:
- UDP协议
- TCP协议
二、IP地址与InetAddress类
- IP地址可以唯一定位一台网络上的计算机
- 127.0.0.1表示的是本机localhost
IP地址分类
InetAddress类
此类表示Internet协议(IP)地址。
通过一些静态方法可以返回一个InetAddress对象代表IP。
InetAddress ip = InetAddress.getByName("www.baidu.com");
三、端口(Port)与 InetSocketAddress
计算机与外界通讯交流的出口
有以下几个特点:
- 不同的进程有不同的端口号,用来区分软件,单个协议下,端口号不能冲突
- TCP、UDP 端口号范围为0~65535
- 端口分类:
- 公有端口:0~1023
- HTTP:80
- HTTPS:443
- FTP:21
- SSH:22
- Telent:23
- 程序注册端口:1024~49151,分配给用户或程序
- Tomcat:8080
- MySQL:3306
- Oracle:1521
- 动态、私有端口:49152~65535
可以通过一些命令来查看端口占用情况:
cmd命令:
netstat -ano #查看所有端口
netstat -ano | findstr "14420" #查看指定端口
tasklist | findstr "11420" #查看指定端口的进程
InetSocketAddress
知道了IP地址,我们可以定位一台主机,
知道了端口号,我们可以定位一个进程,
现在知道了IP地址和端口号,我们可以定位某台计算机上的某个进程。
于是,之前InetAddress的代码就可以做一些改进
InetSocketAddress ip = new InetSocketAddress("www.baidu.com", 443);
四、通信协议
协议就是一些规则,通信协议就是关于通信的规则,如果要通信,那么就必须遵守这些规则
传输层协议
最重要的有TCP协议和UDP协议。
TCP/IP协议族
是指能够在多个不同网络间实现信息传输的协议簇。TCP/IP协议不仅仅指的是TCP和IP两个协议,而是指一个由FTP、SMTP、TCP、UDP、IP等协议构成的协议簇, 只是因为在TCP/IP协议中TCP协议和IP协议最具代表性,所以被称为TCP/IP协议。
TCP协议
传输控制协议
- 客户端和服务端要建立连接,“三次握手,四次挥手”,提供了两台计算机之间可靠无差错的数据传输。可保证传输数据的安全,应用广泛,如上传文件,下载文件,浏览网页。
- 连接、发送数据都需要确认,且传输完毕后,还需要释放已建立的连接,通信效率较低。
UDP协议
- 用户数据报协议
- 客户端和服务端不建立连接,通信效率高,消耗资源小,通常用于音频、视频和普通数据的传输,每次数据包。
TCP
一、TCP实现聊天
因为是C/S架构,所以要有一个客户端和一个服务端。
客户端
public static void main(String[] args) {
InetSocketAddress severIP = new InetSocketAddress("127.0.0.1", 8888);
Socket socket = new Socket();
socket.connect(serverIP);
OutPutStream os = socket.getOutPutSteam();
PrintStream ps = new PrintStream(os);
Scanner in = new Scanner(System.in);
while (true) {
System.out.println("请输入消息:");
ps.println(in.nextLine());
ps.flush();
}
}
服务端
public static void main(String[] args) {
ServerSocket server = new ServerSocket(8888);
Socket socket = server.accept();
InputStream is = socket.getInPutStream();
BufferedReader rd = new BufferedRead(new InputStreamReader(is));
String s;
while ((s = rd.readLine()) != null) {
System.out.println(new Date + "\n" + s);
}
}
二、TCP实现文件上传
文件上传依然是IO流传输数据
消息是一种数据,图片也是一种数据,万物都是数据,所以步骤都是一样的
客户端
public static void main(String[] args) {
Socket socket = new Socket();
socket.connect(new InetSocketAddress("127.0.0.1", 9957));
FileInputStream fos = new FileInputStream("地址");
BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
byte[] buffer = new byte[1024];
int len;
while ((len = fos.read(buffer)) != -1) {
bos.write(buffer, 0, len);
}
socket.shutdownOutput();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
System.out.println(bufferedReader.readLine());
fis.close();
bos.close();
socket.close();
}
服务端
public static void main(String[] args) {
ServerSocket server = new ServerSocket(9957);
Socket socket = server.accept();
FileOutputStream fos = new FileOutputStream("地址");
BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
byte[] buffer = new byte[1024];
int len;
while ((len = bis.read(buffer)) != -1) {
fos.write(buffer, 0, len);
}
PrintStream ps = new PrintStream(socket.getOutputStream());
ps.println("接收完毕!");
fos.close();
bis.close();
socket.close();
}
UDP
UDP不需要连接,知道了目标的地址就可以发消息。
一、UDP消息发送
发送端
- 创建发送端的Socket对象 DatagramSocket
- 创建数据,并将数据打包
- 调用DatagramSocket对象的方法发送数据
- 关闭发送端
public class Client {
public static void main(String[] args) throws IOException {
DatagramSocket datagramSocket = new DatagramSocket();
String s = "hello udp";
DatagramPacket packet = new DatagramPacket(s.getBytes(), 0, s.getBytes().length, InetAddress.getByName("127.0.0.1"), 9957);
datagramSocket.send(packet);
datagramSocket.close();
}
}
接收端
- 创建接收端的Socket对象 DatagramSocket
- 创建一个数据包,用于接收数据
- 调用DatagramSocket对象的方法接收数据
- 解析数据包,并把数据再控制台显示
- 关闭接收端
public static void main(String[] args) throws IOException {
DatagramSocket datagramSocket = new DatagramSocket(9957);
byte[] buffered = new byte[1024];
DatagramPacket packet = new DatagramPacket(buffered, 0, buffered.length);
datagramSocket.receive(packet);
System.out.println(packet.getAddress());
System.out.println(new String(packet.getData(),0, packet.getLength()));
datagramSocket.close();
}
二、UDP实现聊天
只需要把上面的代码稍微改一下即可。
循环输入,以及持久监听。
发送端
public static void main(String[] args) throws IOException {
DatagramSocket socket = new DatagramSocket();
DatagramPacket packet;
Scanner in = new Scanner(System.in);
String s;
do {
System.out.print("Say:");
s = in.nextLine();
packet = new DatagramPacket(s.getBytes(), 0, s.getBytes().length, new InetSocketAddress("127.0.0.1", 9957));
socket.send(packet);
} while (s.compareTo("exit") != 0);
socket.close();
}
接收端
public static void main(String[] args) throws IOException {
DatagramSocket socket = new DatagramSocket(9957);
DatagramPacket packet;
byte[] bufferd = new byte[1024];
while (true) {
packet = new DatagramPacket(bufferd, 0, bufferd.length);
socket.receive(packet);
System.out.println(new String(packet.getData(), 0, packet.getLength()));
}
}
三、多线程UDP聊天程序
发数据需要一个发送端,收数据需要一个接收端
于是先把接收端和发送端的类。
发送端
public class TalkSend implements Runnable {
private DatagramSocket socket;
private DatagramPacket packet;
private BufferedReader reader;
private String toIP;
private int toPort;
private String name;
public TalkSend(String toIP, int toPort, String name) {
this.toIP = toIP;
this.toPort = toPort;
this.name = name;
try {
reader = new BufferedReader(new InputStreamReader(System.in));
socket = new DatagramSocket();
socket.connect(new InetSocketAddress(toIP, toPort));
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void run() {
String s;
while (true) {
try {
s = name + ": " + reader.readLine();
packet = new DatagramPacket(s.getBytes(), 0, s.getBytes().length);
socket.send(packet);
if (s.endsWith(": bye")) {
break;
}
} catch (Exception e) {
e.printStackTrace();
}
}
socket.close();
}
}
接收端
public class TalkReceive implements Runnable {
private DatagramSocket socket;
private DatagramPacket packet;
private int myPort;
public TalkReceive(int myPort) {
this.myPort = myPort;
try {
socket = new DatagramSocket(myPort);
} catch (Exception e){
e.printStackTrace();
}
}
@Override
public void run() {
String s;
byte[] buffered = new byte[1024];
while (true) {
try {
packet = new DatagramPacket(buffered, 0, buffered.length);
socket.receive(packet);
} catch(Exception e) {
e.printStackTrace();
}
s = new String(packet.getData(), 0, packet.getLength());
System.out.println(s);
if (s.endsWith(": bye")) {
break;
}
}
}
}
完成
有了发送端和接收端,我们就可以把他们都丢进线程池中,这样我们就可以和另一台主机通信了。
public class Demo {
public static void main(String[] args) {
ExecutorService pool = new ThreadPoolExecutor(4, 8, 2, TimeUnit.MINUTES, new ArrayBlockingQueue<>(4), Executors.defaultThreadFactory(), new ThreadPoolExecutor.CallerRunsPolicy());
Scanner in = new Scanner(System.in);
System.out.println("设置接收端口:");
int port = in.nextInt();
System.out.println("目标IP:");
String toIP = in.next();
System.out.println("目标端口:");
int toPort = in.nextInt();
System.out.println("您的昵称:");
String name = in.next();
pool.execute(new TalkReceive(port));
pool.execute(new TalkSend(toIP, toPort, name));
}
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)