一、网络编程概述:
1.计算机网络:
是指将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来,在网络操作系统,网络管理软件及网络通信协议的管理和协调下,实现资源共享和信息传递的计算机系统。
2.网络编程:
就是用来实现网络互连的不同计算机上运行的程序间可以进行数据交换。
二:网络编程的三要素:
1.IP
每个设备在网络中的唯一标识,每台网络终端在网络中都有一个独立的地址,在网络中传输数据时使用这个地址。
- ipconfig命令查看本机IP地址
- ping命令检查网络是否连通
2.端口
每个程序在设备上的唯一标识,每个网络程序都需要绑定一个端口号,端口号范围从0-65535,编写网络应用就需要绑定一个端口号,尽量使用1024以上的,1024以下的基本上都被系统程序占用了。
3.协议
为计算机网络中进行数据交换而建立的规则、标准或约定的集合。
- UDP:面向无连接,数据不安全,速度快。不区分客户端与服务端。
-
TCP:面向连接(三次握手),数据安全,速度略低。分为客户端和服务端。
三次握手: 客户端先向服务端发起请求, 服务端响应请求, 传输数据
三次握手简图.png
三、Socket通信原理
1.Socket套接字概述:
网络上具有唯一标识的IP地址和端口号组合在一起才能构成唯一能识别的标识符套接字。
2.原理:
*通信的两端都有Socket
*网络通信其实就是Socket间的通信
*数据在两个Socket间通过IO流传输
*Socket在应用程序中创建,通过一种绑定机制与驱动程序建立关系,告诉自己所对应的IP和port
四、网络编程UDP传输
进行数据传输时,首先将要传输的数据定义成数据报(Datagram),大小限制在64k,在数据报中指明数据索要达到的Socket(主机地址和端口号),然后再将数据报发送出去
DatagramPacket类:此类表示数据报包
DatagramSocket类:此类表示用来发送和接收数据报包的套接字
步骤:
1.发送Send(客户端)
* 创建DatagramSocket, 随机端口号 (也可以指定端口)
* 创建DatagramPacket, 指定数据, 长度, 地址, 端口
* 这里的地址可以填写自己本机地址InetAddress.getByName("xx.xx.xxx.xx")
* 使用DatagramSocket发送DatagramPacket
* 关闭DatagramSocket
package javasocket;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
public class TestSend1 {
public static void main(String[] args) throws Exception {
//创建DatagramSocket, 随机端口号
DatagramSocket socket=new DatagramSocket();
//创建DatagramPacket, 指定数据, 长度, 地址, 端口
DatagramPacket packet=new DatagramPacket("请问在么?".getBytes(),
"请问在么?".getBytes().length,InetAddress.getByName("xx.xx.xxx.xx"),12345);
//使用DatagramSocket发送DatagramPacket
socket.send(packet);
//关闭DatagramSocket
socket.close();
}
}
优化后代码(手动输出发送内容):
public class TestSend2 {
public static void main(String[] args) throws Exception {
//创建DatagramSocket, 随机端口号
DatagramSocket socket=new DatagramSocket();
//键盘录入对象
Scanner scanner=new Scanner(System.in);
while(true) {
String str = scanner.nextLine();
if (str.equals("quit")) {
break;
}
//创建DatagramPacket, 指定数据, 长度, 地址, 端口
DatagramPacket packet=new DatagramPacket(str.getBytes(),
str.getBytes().length,InetAddress.getByName("xx.xx.xxx.xx"),12345);
//使用DatagramSocket发送DatagramPacket
socket.send(packet);
//关闭DatagramSocket
}
socket.close();
}
}
2.接收Receive(服务端)
*创建DatagramSocket, 指定端口号
*创建DatagramPacket, 指定数组, 长度
*使用DatagramSocket接收DatagramPacket
*关闭DatagramSocket
*从DatagramPacket中获取数据
3.接收方获取ip和端口号
*String ip = packet.getAddress().getHostAddress();
*int port = packet.getPort();
package javasocket;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
public class TestService {
public static void main(String[] args) throws Exception {
// 创建DatagramSocket, 指定端口号
DatagramSocket socket = new DatagramSocket(12345);
// 创建DatagramPacket, 指定数组, 长度
DatagramPacket packet = new DatagramPacket(new byte[1024], 1024);
// 使用DatagramSocket接收DatagramPacket
socket.receive(packet);
byte[] data = packet.getData();// 返回数据缓冲区返回数组形式
String string = new String(data, 0, packet.getLength());// 转成中文
System.out.println(packet.getAddress() + "--" + packet.getPort() + "--" + string);
// 关闭DatagramSocket
socket.close();
}
}
优化后代码(手动输入发送内容):
public class TestService2 {
public static void main(String[] args) throws Exception {
// 创建DatagramSocket, 指定端口号
DatagramSocket socket = new DatagramSocket(12345);
// 创建DatagramPacket, 指定数组, 长度
DatagramPacket packet = new DatagramPacket(new byte[1024], 1024);
while(true) {
// 使用DatagramSocket接收DatagramPacket
socket.receive(packet);
byte[] data = packet.getData();// 获取数据,返回数据缓冲区返回数组形式
String string = new String(data, 0, packet.getLength());// 转成字符串
System.out.println(packet.getAddress() + "--" + packet.getPort() + "--" + string);
}
}
}
如果想将客户端和服务端写在同一个代码里,就可以直接创建两个线程来完成,代码如下:
public class UdpThread {
public static void main(String[] args) {
new Thread() {
public void run() {
try {
// 创建DatagramSocket, 指定端口号
DatagramSocket socket = new DatagramSocket(12345);
// 创建DatagramPacket, 指定数组, 长度
DatagramPacket packet = new DatagramPacket(new byte[1024], 1024);
while(true) {
// 使用DatagramSocket接收DatagramPacket
socket.receive(packet);
byte[] data = packet.getData();// 获取数据,返回数据缓冲区返回数组形式
String string = new String(data, 0, packet.getLength());// 转成字符串
System.out.println(packet.getAddress() + "--" + packet.getPort() + "--" + string);
}
} catch (Exception e) {
}
}
}.start();
new Thread() {
public void run() {
try {
//创建DatagramSocket, 随机端口号
DatagramSocket socket=new DatagramSocket();
//键盘录入对象
Scanner scanner=new Scanner(System.in);
while(true) {
String str = scanner.nextLine();
if (str.equals("quit")) {
break;
}
//创建DatagramPacket, 指定数据, 长度, 地址, 端口
DatagramPacket packet=new DatagramPacket(str.getBytes(),
str.getBytes().length,InetAddress.getByName("xx.xx.xxx.xx"),12345);
//使用DatagramSocket发送DatagramPacket
socket.send(packet);
//关闭DatagramSocket
}
socket.close();
} catch (Exception e) {
// TODO: handle exception
}
}
}.start();
}
}
五、网络编程TCP传输
通过三次握手方式建立连接,形成传输数据的通道,在连接中进行大量数据的传输,效率会稍低.
步骤:
1.客户端
* 创建Socket连接服务端(指定ip地址,端口号)通过ip地址找对应的服务器
* 调用Socket的getInputStream()和getOutputStream()方法获取和服务端相连的IO流
* 输入流可以读取服务端输出流写出的数据
* 输出流可以写出数据到服务端的输入流
public class Send1 {
public static void main(String[] args) throws Exception, IOException {
// 创建Socket连接服务端(指定ip地址,端口号)通过ip地址找对应的服务器
Socket socket = new Socket("xx.xx.xxx.xx", 54321);
// 获取输入流,输入流可以读取服务端输出流写出的数据
InputStream is = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));// 封装
// 获取输出流,输出流可以写出数据到服务端的输入流
OutputStream os = socket.getOutputStream();
// 获取字符流
PrintStream ps = new PrintStream(os);
ps.println("你好!");
String str = br.readLine();
System.out.println(str);
ps.print("是的,我需要帮助。");
socket.close();
}
}
2.服务端
* 创建ServerSocket(需要指定端口号)
* 调用ServerSocket的accept()方法接收一个客户端请求,得到一个Socket
* 调用Socket的getInputStream()和getOutputStream()方法获取和客户端相连的IO流
* 输入流可以读取客户端输出流写出的数据
* 输出流可以写出数据到客户端的输入流
public class Service1 {
public static void main(String[] args) throws Exception {
// 创建ServerSocket(需要指定端口号)
ServerSocket ss = new ServerSocket(54321);
// 调用ServerSocket的accept()方法接收一个客户端请求,得到一个Socket
Socket accept = ss.accept();
// 调用Socket的getInputStream()和getOutputStream()方法获取和客户端相连的IO流
// 获取输入流,输入流可以读取客户端输出流写出的数据
InputStream is = accept.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));// 封装
// 获取输出流,输出流可以写出数据到客户端的输入流
OutputStream os = accept.getOutputStream();
PrintStream ps = new PrintStream(os);
String str = br.readLine();
System.out.println(str);
ps.println("你好,有什么需要帮助的么?");
String str1 = br.readLine();
System.out.println(str1);
}
}
服务端是多线程的,代码如下:
public class Service1 {
public static void main(String[] args) throws Exception {
// 创建ServerSocket(需要指定端口号)
ServerSocket ss = new ServerSocket(54321);
while (true) {
// 调用ServerSocket的accept()方法接收一个客户端请求,得到一个Socket
Socket accept = ss.accept();
new Thread() {
public void run() {
try {
// 调用Socket的getInputStream()和getOutputStream()方法获取和客户端相连的IO流
// 获取输入流,输入流可以读取客户端输出流写出的数据
InputStream is = accept.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));// 封装
// 获取输出流,输出流可以写出数据到客户端的输入流
OutputStream os = accept.getOutputStream();
PrintStream ps = new PrintStream(os);
String str = br.readLine();
System.out.println(str);
ps.println("你好,有什么需要帮助的么?");
String str1 = br.readLine();
System.out.println(str1);
} catch (Exception e) {
}
};
}.start();
}
}
}
如有错误请及时纠正我,谢谢。
此文章仅作为个人学习笔记用。
网友评论