第十一章 网络编程
1. 提纲
值得注意的是网络编程不等同于网站编程


2. 网络基础概念

3. 网络通信协议及接口

4. 数据分层的思想


5. 数据封装和数据拆封


6. IP协议

IPV4协议中用4个字节表示IP地址,故每位的值最大不超过255。
IP由网络段+主机段两部分组成 ;又根据网络段所占字节数分为:A类网(1个字节)、B类网(2个字节)、C类网(3个字节)等。
子网掩码(subnet mask)又叫网络掩码、地址掩码、子网络遮罩,它是一种用来指明一个IP地址的哪些位标识的是主机所在的子网,以及哪些位标识的是主机的位掩码。子网掩码不能单独存在,它必须结合IP地址一起使用。子网掩码只有一个作用,就是将某个IP地址划分成网络地址和主机地址两部分。
网关(Gateway)又称网间连接器、协议转换器。默认网关在网络层上以实现网络互连,是最复杂的网络互连设备,仅用于两个高层协议不同的网络互连。网关的结构也和路由器类似,不同的是互连层。网关既可以用于广域网互连,也可以用于局域网互连。
根据子网掩码判断主机是否在一个网络上
子网掩码详解
7. TCP/UDP协议

TCP可靠但是慢,UDP不可靠但是快;如CF游戏射击子弹时是使用的就是UDP协议,因为可以丢包(对方卡了)。
8. Socket协议
- TCP协议


- 端口号占两个字节最多65536个,而端口号也分TCP和UDP两种。自己编写程序时用1024以上的端口号,1024以下的端口号系统随时征用。
- TCP上的服务端(server端)使用ServerSocket,客户端(client端)使用Socket。程序成对出现。程序启动时要先启动Server端再启动Client端。
例子1(服务器端):
import java.net.*;
import java.io.*;
public class TestServer {
public static void main(String[] args) {
try{
ServerSocket ss = new ServerSocket(8888); //服务器端8888接口用来与某个客户端进行互访
while(true) { //死循环保证服务器端时刻准备连接,不会宕机
Socket s = ss.accept(); //accept()方法与客户端实现连接
OutputStream os = s.getOutputStream(); //获取服务器端的输出流
DataOutputStream dos = new DataOutputStream(os); //进行包装
dos.writeUTF("Hello," + s.getInetAddress() //输出流里写入
+ "port#" + s.getPort() + " bye-bye!!");
dos.close(); //关闭数据流
s.close(); //关闭套接字
}
} catch(IOException e) {
e.printStackTrace();
System.out.println("Program is ERROR" + e);
}
}
}
例子1(客户端):
import java.net.*;
import java.io.*;
public class TestClient {
public static void main (String[] args) {
try {
Socket s = new Socket("127.0.0.1",8888); //设置服务端地址,及客户端与服务端连接的端口号
InputStream is = s.getInputStream(); //获取客户端输入流
DataInputStream dis = new DataInputStream(is); //包装输入流
System.out.println(dis.readUTF()); //读取输入流的内容
dis.close(); //关闭输入流
s.close(); //关闭套接字
} catch(ConnectException ce) {
ce.printStackTrace();
System.out.println("Server Connect is ERROR");
} catch(IOException e) {
e.printStackTrace();
}
}
}
例子2(服务器端):
import java.net.*;
import java.io.*;
public class TestSocketServer {
public static void main(String[] args){
try {
ServerSocket ss = new ServerSocket(5888);
Socket socket = ss.accept();
InputStream is = socket.getInputStream();
OutputStream os = socket.getOutputStream();
DataInputStream dis = new DataInputStream(is);
DataOutputStream dos = new DataOutputStream(os);
String s = null;
if((s=dis.readUTF())!= null) {
System.out.println(s);
System.out.println("Form:" + socket.getInetAddress());
System.out.println("Port:" + socket.getPort());
}
dos.writeUTF("hi,hello");
dis.close();
dos.close();
socket.close();
} catch(IOException e) {
e.printStackTrace();
}
}
}
例子2(客户端):
import java.net.*;
import java.io.*;
public class TestSocketClient {
public static void main(String[] args) {
try {
Socket socket = new Socket("127.0.0.1",5888);
InputStream is = socket.getInputStream();
OutputStream os = socket.getOutputStream();
DataInputStream dis = new DataInputStream(is);
DataOutputStream dos = new DataOutputStream(os);
dos.writeUTF("hi");
String s = null;
if((s=dis.readUTF()) != null) {
System.out.println(s);
}
dos.close();
dis.close();
socket.close();
} catch(UnknownHostException e) {
e.printStackTrace();
} catch(IOException e) {
e.printStackTrace();
}
}
}
例子3(服务器端):
import java.io.*;
import java.net.*;
public class TestTalkServer {
public static void main(String[] args) {
try {
ServerSocket ss = new ServerSocket(6688);
Socket socket = ss.accept();
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter pw = new PrintWriter(socket.getOutputStream());
BufferedReader brs = new BufferedReader(new InputStreamReader(System.in));
System.out.println("Client:" + br.readLine());
if(br.readLine()== null) {
System.out.println("Clinet exit Connection!!");
br.close();
brs.close();
pw.close();
socket.close();
ss.close();
} else{
String s = brs.readLine();
while(!s.equals("bye")) {
pw.println(s);
pw.flush();
System.out.println("Server:" + s);
System.out.println("Client:" + br.readLine());
s = brs.readLine();
}
br.close();
brs.close();
pw.close();
socket.close();
ss.close();
}
} catch(IOException e) {
System.out.println("ERROR");
e.printStackTrace();
}
}
}
例子3(客户端):
import java.io.*;
import java.net.*;
public class TestTalkClient {
public static void main(String[] args) {
try {
Socket socket = new Socket("127.0.0.1",6688);
BufferedReader brs = new BufferedReader(new InputStreamReader(System.in));
PrintWriter pw = new PrintWriter(socket.getOutputStream());
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String s = brs.readLine();
while (!s.equals("bye")) {
pw.println(s);
pw.flush();
System.out.println("Client:" + s);
System.out.println("Server:" + br.readLine());
s = brs.readLine();
}
pw.close();
br.close();
brs.close();
socket.close();
} catch(IOException e) {
System.out.println("ERROR");
e.printStackTrace();
}
}
}
- UDP协议

UDP协议在使用过程中没有实际意义上的ServerSocket和Socket,只存在逻辑意义上的。程序成对出现。
例子1(逻辑意义服务端):
import java.net.*;
public class TestUDPServer {
public static void main(String[] args) {
try {
byte[] buf = new byte[1024]; //创建一个大小为1024的字符数组,用来装接受来的数据。
DatagramPacket dp = new DatagramPacket(buf,buf.length); //将数据打成数据包。
DatagramSocket ds = new DatagramSocket(8866); //用8866端口接收数据
while(true) { //死循环,无限循环
ds.receive(dp); //接收传过来的数据包
System.out.println(new String(buf,0,dp.getLength())); //屏幕输出
}
} catch(Exception e) {
System.out.println("ERROR");
e.printStackTrace();
}
}
}
例子1(逻辑意义客户端):
import java.net.*;
public class TestUDPClient {
public static void main(String[] args) {
try {
byte[] buf = (new String("Hello")).getBytes(); //将字符串转换成字符数组
DatagramPacket dp = new DatagramPacket(buf,buf.length,new InetSocketAddress("127.0.0.1",8866)); //将数据打成数据包向本机的8866端口传送
DatagramSocket ds = new DatagramSocket(9999); //由9999端口送出
ds.send(dp); //发送数据包
ds.close();
} catch(Exception e) {
System.out.println("ERROR");
e.printStackTrace();
}
}
}
例子2(如何传送一个long类型的数字)(逻辑意义服务器端):
import java.net.*;
import java.io.*;
public class TestUDPLongServer {
public static void main(String[] args) {
try {
byte[] buf = new byte[1024];
DatagramPacket dp = new DatagramPacket(buf,buf.length);
DatagramSocket ds = new DatagramSocket(5678);
while(true) {
ds.receive(dp);
ByteArrayInputStream bais = new ByteArrayInputStream(buf);
DataInputStream dis = new DataInputStream(bais);
System.out.println(dis.readLong());
}
} catch(Exception e) {
System.out.println("ERROR");
}
}
}
例子2(如何传送一个long类型的数字)(逻辑意义客户端):
import java.io.*;
import java.net.*;
public class TestUDPLongClient {
public static void main(String[] args) {
try{
long l = 10000L;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(baos);
dos.writeLong(l);
byte[] buf = baos.toByteArray(); //toByteArray()创造一个输出流大小内容相同的字符数组
System.out.println(buf.length);
DatagramPacket dp = new DatagramPacket(buf,buf.length,new InetSocketAddress("127.0.0.1",5678));
DatagramSocket ds = new DatagramSocket(9999);
ds.send(dp);
ds.close();
} catch(Exception e) {
System.out.println("ERROR");
}
}
}
9. 总结

注:本博客由溺水狗原创但其学习资源资料来源于网络(马士兵老师的教学视频),特此感谢马士兵老师
本文深入讲解网络编程核心概念,包括网络通信协议、IP协议、TCP/UDP协议、Socket编程及其实例,涵盖数据分层、封装与拆封,子网掩码与网关解析,适合初学者与进阶开发者。
147

被折叠的 条评论
为什么被折叠?



