引言
所谓网络编程,指的就是通过编写程序使得计算机可以相互通信,生活中很多软件都是融合了网络编程的,比如QQ 等通信app。网络编程通常是为现有App增强连接到服务端的能力,但是有些事基于TCP,有些是基于HTTP。狭义的网络编程,指的是通信聊天类型的应用,广义的是凡是接入网络的程序,都是网络编程。
一.网络基础知识
1.1 网络模型
网络通信最初的设计模型为OSI 7层通信模型,所谓网络模型就是科学家对应如何实现网络通信的一种设计和设想。一个科学领域的某些技术往往都是先建立问题模型,然后再做实现。
1.1.1 OSI模型
1.1.2 TCP/IP模型
1.2 IP地址
IP 也就是IP地址协议,它的作用就是标记网络中每台计算机的身份。网络中的每个计算机都有唯一的一个地址。
1.2.1 IP地址表示
- IPv4
它是由一个4字节32位的整数表示,为了方便记忆,使用点分10进制表示D.D.D.D,每8位使用一个0-255表示,用 . 分隔。 平时见到的 如192.128.1.12 这种就是 IPv4地址表示。
由于 表示容量的 问题 ,IPv4 早已不够使用,它的下一个版本IPv6 拥有更大的表示范围。
- IPv6
它是由一个16字节128位的整数表示,表示的范围更大,也就意味着IP地址越多,夸张到 沙漠中每一粒沙子都可以分配到一个IP,它使用8段16进制表示,每段0-65535。X.X.X.X.X.X.X.X 。
1.2.2 IP地址分类
1.3 端口
端口,计算机上通信程序的唯一标识,计算机中存在多网络软件,如何区分开不同的软件,就需要使用端口。不同的应用只通过固定端口收发数据。
端口的范围 0-65535
1.3.1 常见默认端口
MySQL-> 3306
Tomcat->8080
HTTP->80
SSH->22
FTP->21
1.4 TCP/UDP
1.4.1 TCP 特点
1)TCP是面向连接的运输层协议。应用程序在使用TCP协议之前,必须先建立TCP连接,在传送数据完毕后,必须释放已经建立的TCP连接。
(2)每一条TCP连接只能有两个端点,即点对点的。
(3)TCP提供可靠交付的服务。通过TCP连接传送的数据,无差错、不丢失、不重复、并且按序到达。
(4)TCP提供全双工通信。TCP允许通信双方的应用进程在任何时候都能发送数据。
(5)面向字节流。TCP中的“流”指的是流入到进程或从进程流出的字节序列。面向字节流的含义是:虽然应用程序和TCP的交互是一次一个数据块(大小不等),但是TCP把应用程序交下来的数据仅仅看成是一连串的无结构的字节流。
1.4.2 UDP 特点
(1)UDP是无连接的,即发送数据之前不需要建立连接(当然,发送数据结束时也没有连接可以释放),因此减少了开销和发送数据之前的时延。
(2)UDP使用尽最大努力交付,即不保证可靠交付,因此主机不需要维持复杂的连接状态表(这里面有很多参数)。
(3)UDP是面向报文的。发送方的UDP对应用程序交下来的报文,在添加首部后就向下交付IP层。UDP对应用层交下来的报文,既不合并,也不拆分,而是保留这些报文的边界。这就是说,应用层交给UDP多长 的报文,UDP就照样发送,即一次发送一个报文。
(4)UDP没有拥塞控制,因此网络出现的拥塞不会使源主机的发送速率降低。但是不使用拥塞控制功能的UDP有可能会引起网络产生严重的拥塞问题。
(5)UDP支持一对一、一对多、多对一和多对多的交互通信。
(6)UDP的首部开销小,只有8个字节,比TCP的20个字节的首部还要短。
UDP也用在路由信息协议RIP(Routing Information Protocol)中修改路由表。在这些应用场合下,如果有一个消息丢失,在几秒之后另一个新的消息就会替换它。UDP广泛用在多媒体应用中。
1.4.3 三次握手
1.4.5 四次挥手
二.Socket编程
2.1 Socket 编程流程
- 服务器端使用ServerSocket套接字 并绑定监听端口
- 服务端 阻塞等待连接
- 客户端使用 Socket 并指定服务端IP 和 端口
服务端:
//1. 服务器端套接字
ServerSocket server = new ServerSocket(8848);
//2. 监听客户端连接
Socket socket = server.accept();
客户端
//1. 创建客户端套接字
Socket socket = new Socket( "127.0.0.1" , 8848);
2.2 Socket 收发数据
从Socket中读数据
InputStream is = socket.getInputStream();
byte[] buff = new byte[1024];
int len=0;
while ( (len=is.read(buff))!=-1){
//读到了客户端发的字节信息
System.out.println( new String(buff,0,len) );
}
从写数据到Socket中
//发送数据给服务端
BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
bos.write("hello".getBytes());
2.3 多客户端连接
while (true) {
System.out.println("等待连接中.......");
//接收客户端连接
Socket socket = server.accept();
}
2.4 多客户端通信
//服务端
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
@SuppressWarnings("all")
public class sever {
public static List<Socket> socketList = new ArrayList<>();
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(7777);
while (true){
System.out.println("等待客户端连接");
Socket socket = serverSocket.accept();
socketList.add(socket);
//在这里读数据阻塞线程,在这里启动一个新的线程单独处理读取这个客户端的信息
new Thread(new serverThread(socket)).start();
}
}
}
class serverThread implements Runnable{
private Socket socket;
//构建任务时初始化客户端
public serverThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try{
InputStream is = socket.getInputStream();
byte[] bs = new byte[1024];
int len;
while (( len=is.read(bs))!=-1){
String msg = new String(bs,0,len);
for (Socket socket1 : sever.socketList) {
if (socket1==this.socket)continue;
socket1.getOutputStream().write(msg.getBytes());
}
}
}catch(IOException e){
e.printStackTrace();
}
}
}
//客户端
package NET3;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;
public class client {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("127.0.0.1",7777);
OutputStream outputStream = socket.getOutputStream();
new Thread(new clientThread(socket)).start();
//防止客户端关闭 服务端接收不了 socket 写个while()
while (true){
Scanner sc = new Scanner(System.in);
String str= sc.nextLine();
outputStream.write(str.getBytes());
}
}
}
class client2{
public static void main(String[] args) throws IOException {
Socket socket = new Socket("127.0.0.1",7777);
OutputStream outputStream = socket.getOutputStream();
new Thread(new clientThread(socket)).start();
//防止客户端关闭 服务端接收不了 socket 写个while()
while (true){
Scanner sc = new Scanner(System.in);
String str= sc.nextLine();
outputStream.write(str.getBytes());
}
}
}
class client3{
public static void main(String[] args) throws IOException {
Socket socket = new Socket("127.0.0.1",7777);
OutputStream outputStream = socket.getOutputStream();
new Thread(new clientThread(socket)).start();
//防止客户端关闭 服务端接收不了 socket 写个while()
while (true){
Scanner sc = new Scanner(System.in);
String str= sc.nextLine();
outputStream.write(str.getBytes());
}
}
}
class clientThread implements Runnable{
private Socket socket;
public clientThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
InputStream is = socket.getInputStream();
byte[] bs = new byte[1024];
int len;
while ((len = is.read(bs))>0){
String msg = new String(bs,0,len);
System.out.println(msg);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
案例:
客户端与服务端 形成翻译软件类型
package cidian;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Properties;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.net.Socket;
import java.util.Scanner;
//客户端
class client {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("127.0.0.1",2345);
Scanner sc = new Scanner(System.in);
System.out.println("请输入单词:");
String filename = sc.next();
PrintStream ps = new PrintStream(socket.getOutputStream());
ps.println(filename);
InputStream is = socket.getInputStream();
byte[] bs = new byte[1024];
int len;
while((len=is.read(bs))>0){
String msg = new String(bs,0,len);
System.out.println(msg);
}
System.out.println("传输完毕");
}
}
//服务器端
public class server {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(2345);
while (true){
System.out.println("等待连接......");
Socket socket = serverSocket.accept();
new Thread(new serverThread(socket)).start();
}
//接受客户端发的文件名
}
}
class serverThread implements Runnable{
private Socket socket;
public serverThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
//读到单词
BufferedReader bf = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String keywords = bf.readLine();
Properties properties = new Properties();
properties.load(new FileReader("C:\\Users\\杨嘿嘿\\.IntelliJIdea2019.3\\config\\scratches\\words.properties"));
String value = properties.getProperty(keywords);
if (value!=null){
socket.getOutputStream().write(value.getBytes());
}else {
socket.getOutputStream().write("词典里面没有这个词".getBytes());
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
作业:
客户端输入一个文件名 服务端接受 然后查找本地有没有这个文件 有的话 就把文件返回给客户端
//服务端
package net4;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Arrays;
public class server {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(2345);
while (true){
System.out.println("等待连接......");
Socket socket = serverSocket.accept();
new Thread(new serverThread(socket)).start();
}
//接受客户端发的文件名
}
}
class serverThread implements Runnable{
private Socket socket;
public serverThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
File file = new File("C:\\Users\\杨嘿嘿\\Desktop");
BufferedReader bf = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//读出文件名
String filename = bf.readLine();
//获取文件夹下的文件名数组
String[] list = file.list();
//将它转为list
ArrayList<String> arrayList = new ArrayList<String>(Arrays.asList(list)) ;
if (arrayList.contains(filename)){
FileInputStream fis = new FileInputStream("C:\\Users\\杨嘿嘿\\Desktop\\"+filename);
byte[] bs = new byte[2048];
int len;
while ((len=fis.read(bs))>0){
socket.getOutputStream().write(bs,0,len);
}
System.out.println("传输完毕");
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
//客户端
package net4;
import java.io.*;
import java.net.Socket;
import java.util.Scanner;
public class client {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("127.0.0.1",2345);
Scanner sc = new Scanner(System.in);
System.out.println("请输入文件名:");
String filename = sc.next();
PrintStream ps = new PrintStream(socket.getOutputStream());
ps.println(filename);
InputStream is = socket.getInputStream();
FileOutputStream ous = new FileOutputStream("server_"+filename);
byte[] bs = new byte[1024];
int len;
while((len=is.read(bs))>0){
ous.write(bs,0,len);
}
System.out.println("传输完毕");
ous.close();
}
}