1、目标
理解网络相关概念
会使用基于TCP协议的Socket编程
会使用基于UDP协议的Socket编程
2、IP地址
什么是IP地址?为什么需要IP地址?
两台计算机通信,双方都必须有地址,而这个地址就是Ip地址
IP地址(Internet Protocol)
唯一表示网络上的每一台计算机
IP地址的组成
32为,由4个8位二进制数组成
IP地址 = 网络地址 + 主机地址
网络地址: 标识计算机或网络设备所在的网段
主机地址: 标识特定主机或网络设备
IP地址的配置和检测
查看IP地址,检测网络是否畅通
查看本机的IP地址
可以使用命令 ifconfig
测试网络是否畅通
命令: ping 目标IP地址
DNS域名解析
DNS:Domain Name System,域名系统
访问网站的时候为什么输入的是网址而不是IP地址?
域名系统(DNS)就是起到网址与IP地址之间转换的作用。当用户在浏览器中输入网址后,DNS服务器会将这个易于记忆的网址转换成服务器对应的IP地址,然后浏览器才能通过这个IP地址找到并访问网站。所以,虽然最终访问的是IP地址指向的服务器,但是用户界面使用的是更加友好的网址。
网络服务器
通常指在网络环境下,具有较高计算能力,能够提供用户服务功能的计算机
网络通信协议
为了在网络中不同的计算机之间进行通信而建立的规则、标准或约定的集合
Socket
什么是Socket?
两台电脑之间的交互可以想象成物流运送快递的过程,而物流在运送的过程中都会经过中转站,这个中转站我们就可以看成是一个Socket。而在网络编程中,网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket。
通信链路的端点就被称为"套接字" (英文名Socket)
是提供给应用程序的接口
java.net包
Socket
ServerSocket
DatagramPacket
DatagramSocket
InetAddress
基于TCP协议的Socket编程
什么是TCP?
TCP是(Tranfer Control Protocol)的简称,是一种面向连接的保证可靠传输的协议。通过TCP协议传输,得到的是一个顺序的无差错的数据流。发送方和接收方的成对的两个socket之间必须建立连接,当一个socket(通常都是server socket)等待建立连接时,另一个socket可以要求进行连接,一旦这两个socket连接起来,它们就可以进行双向数据传输,双方都可以进行发送或接收操作。
TCP的三次握手
建立起一个TCP连接需要经过"三次握手":第一次握手:客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认;第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。
握手过程中传送的包里不包含数据,三次握手完毕后,客户端与服务器才正式开始传送数据。理想状态下,TCP连接一旦建立,在通信双方中的任何一方主动关闭连接之前,TCP 连接都将被一直保持下去。断开连接时服务器和客户端均可以主动发起断开TCP连接的请求。
基于TCP协议的Socket网络通信
用来实现双向安全连接网络通信
Socket通信模型
进行网络通信时,Socket需要借助数据流来完成数据的传递工作
Socket网络编程一般可以分为如下步骤进行
Socket中实现对象的传递
传递对象信息
序列化
ObjectOutputStream oos = new ObjectOutputStream(...);
oos.writeObject(...);
ObjectInputStream ois = new ObjectInputStream(...);
Object = ois.readObject();
多线程处理多请求
实现多客户请求
采用多线程的方式,一个专门负责监听的应用主服务程序
一个专门负责处理请求的线程程序
基于UDP协议的Socket编程
|-----------|----------|-----------|
| | TCP | UDP |
| 是否连接 | 面向连接 | 面向非连接 |
| 传输可靠性 | 可靠 | 不可靠 |
| 速度 | 慢 | 快 |
基于UDP协议的Socket网络编程步骤
练习
练习一
需求说明模拟用户登录的功能实现客户发送登录用户信息,服务器端显示登录信并响应给客户端登录成功
客户端
package exercise01;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;
/**
* @Author: Insight
* @Description: TODO
* @Date: 2024/9/9 17:07
* @Version: 1.0
*/
public class client {
public static void main(String[] args) {
try {
Socket sk = new Socket("127.0.0.1",8088);
OutputStream os = sk.getOutputStream();
String loginname = "";
String loginpwd = "";
String loginmsg = "";
Scanner sc = new Scanner(System.in);
System.out.println("欢迎来到登录系统");
System.out.print("请输入用户名");
loginname = sc.next();
System.out.println("请输入密码");
loginpwd = sc.next();
loginmsg = loginname + ";" + loginpwd;
os.write(loginmsg.getBytes());
sk.shutdownOutput();
os.close();
sk.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
服务器端
package exercise01;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Arrays;
/**
* @Author: Insight
* @Description: TODO
* @Date: 2024/9/9 17:09
* @Version: 1.0
*/
public class Server {
public static void main(String[] args) {
try {
ServerSocket ssk = new ServerSocket(8088);
Socket sk = ssk.accept();
InputStream is = sk.getInputStream();
System.out.println(is.available());
byte[] b = new byte[1024];
System.out.println(is.read(b));
String msg = new String(b,"UTF-8");
System.out.println(msg);
is.close();
sk.close();
ssk.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
}
}
}
练习二
需求说明升级前一个上机内容,实现多客户端用户登录分析创建服务器端线程类,run()方法中实现对一个请求的响应处理修改服务器端代码,实现循环监听状态服务器端每监听到一个请求,创建一个处理线程
LoginThread
package exercise03;
import java.io.*;
import java.net.Socket;
/**
* @Author: Insight
* @Description: TODO
* @Date: 2024/9/10 15:23
* @Version: 1.0
*/
public class LoginThread extends Thread{
private Socket socket;
public LoginThread(Socket socket){
this.socket = socket;
}
@Override
public void run() {
InputStream is= null;
ObjectInputStream ois = null;
OutputStream os = null;
BufferedWriter bw = null;
try {
is = socket.getInputStream();
ois = new ObjectInputStream(is);
User u = (User) ois.readObject();
System.out.println(u.toString());
System.out.println("用户:" + u.getUsername() + " 登陆成功!!");
// os = socket.getOutputStream();
// bw = new BufferedWriter(new OutputStreamWriter(os));
//
// bw.write("登陆成功!!!");
//
// bw.flush();
} catch (Exception e) {
e.printStackTrace();
}
}
}
User
package exercise03;
import java.io.Serializable;
/**
* @Author: Insight
* @Description: TODO
* @Date: 2024/9/10 15:23
* @Version: 1.0
*/
public class User implements Serializable {
private String username;
private String userpwd;
public User(String username, String userpwd) {
this.username = username;
this.userpwd = userpwd;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getUserpwd() {
return userpwd;
}
public void setUserpwd(String userpwd) {
this.userpwd = userpwd;
}
@Override
public String toString() {
return "User{" +
"username='" + username + '\'' +
", userpwd='" + userpwd + '\'' +
'}';
}
}
UserClient01
package exercise03;
import java.io.*;
import java.net.Socket;
/**
* @Author: Insight
* @Description: TODO
* @Date: 2024/9/10 15:23
* @Version: 1.0
*/
public class UserClient01 {
public static void main(String[] args) {
Socket socket = null;
OutputStream os = null;
ObjectOutputStream oos = null;
InputStream is= null;
BufferedReader br = null;
try {
socket = new Socket("127.0.0.1",8088);
os = socket.getOutputStream();
oos = new ObjectOutputStream(os);
User u = new User("admin","admin");
oos.writeObject(u);
socket.shutdownOutput();
is = socket.getInputStream();
br = new BufferedReader(new InputStreamReader(is));
// byte[] b = new byte[1024];
// String str = new String(b);
System.out.println(br.readLine());
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
oos.close();
os.close();
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
UserClient02
package exercise03;
import java.io.*;
import java.net.Socket;
/**
* @Author: Insight
* @Description: TODO
* @Date: 2024/9/10 15:23
* @Version: 1.0
*/
public class UserClient02 {
public static void main(String[] args) {
Socket socket = null;
OutputStream os = null;
ObjectOutputStream oos = null;
InputStream is= null;
BufferedReader br = null;
try {
socket = new Socket("127.0.0.1",8088);
os = socket.getOutputStream();
oos = new ObjectOutputStream(os);
User u = new User("admin1","admin1");
oos.writeObject(u);
socket.shutdownOutput();
is = socket.getInputStream();
br = new BufferedReader(new InputStreamReader(is));
// byte[] b = new byte[1024];
// String str = new String(b);
System.out.println(br.readLine());
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
oos.close();
os.close();
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
UserServer
package exercise03;
import exercise01.Server;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
/**
* @Author: Insight
* @Description: TODO
* @Date: 2024/9/10 15:23
* @Version: 1.0
*/
public class UserServer {
public static void main(String[] args) {
ServerSocket serverSocket = null;
Socket socket = null;
try {
serverSocket = new ServerSocket(8088);
while(true){
socket = serverSocket.accept();
LoginThread loginThread = new LoginThread(socket);
loginThread.start();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
练习三
需求说明实现客户咨询问题,客服人员答复问题分析咨询时,客户是发送方,客服人员是接收方答复时,客服人员是发送方,客户是接收方,实现思路和咨询时相同
客服回复:server
package exercise04;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketAddress;
import java.net.SocketException;
import java.util.Scanner;
/**
* @Author: Insight
* @Description: 客服回复 这里通过将服务器端设定为客服端来实现二者对话
* @Date: 2024/9/10 15:51
* @Version: 1.0
*/
public class ServiceTest {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String reply = "";
try {
//UDPsocker链接 创建连接端口,默认ip为本地ip
DatagramSocket datagramSocket = new DatagramSocket(8088);
//接收数据包 创建DatagramPacket来创建接收信息的盒子
byte[] b = new byte[1024];
DatagramPacket datagramPacket = new DatagramPacket(b,b.length);
do {
//接收信息 通过atagramSocket.receive来将客户端传递的信息存入datagramPacket中
datagramSocket.receive(datagramPacket);
//读取出datagramPacket中的信息
String str1 = new String(datagramPacket.getData(),0,datagramPacket.getLength());
System.out.println("客服回复:" + str1);
if (str1 != null){
//给客户端回应
System.out.println("请输入内容");
reply = sc.next();
byte[] b1 = reply.getBytes();
//获取客户端地址 通过getSocketAddress来获取客户端的ip地址,以便重新发回信息
SocketAddress sa = datagramPacket.getSocketAddress();
//打包信息 将需要回复的信息存入DatagramPacket中,并发回信息
DatagramPacket datagramPacket1 = new DatagramPacket(b1,0,b1.length,sa);
datagramSocket.send(datagramPacket1);
}
if(reply.equals("再见")) {
break;
}
}while(true);
} catch (Exception e) {
e.printStackTrace();
}
}
}
客户询问:Client
package exercise04;
import java.net.*;
import java.util.Scanner;
/**
* @Author: Insight
* @Description: TODO
* @Date: 2024/9/10 15:51
* @Version: 1.0
*/
public class UserClient01 {
public static void main(String[] args) {
System.out.println("客户咨询0.0.0.0.");
Scanner sc= new Scanner(System.in);
String ask = "";
do {
//开始询问
System.out.println("请输入您要咨询的问题");
ask = sc.next();
byte[] b = ask.getBytes();
// DatagramPacket datagramPacket = new DatagramPacket(b,0,b.length);
DatagramSocket socket=null;
InetAddress ia= null;
try {
ia = InetAddress.getByName("127.0.0.1");
//打包信息发送
DatagramPacket datagramPacket = new DatagramPacket(b,0,b.length,ia,8088);
socket = new DatagramSocket();
//发送消息
socket.send(datagramPacket);
//接收回复信息
byte[] b1= new byte[1024];
DatagramPacket datagramPacket1 = new DatagramPacket(b1,0,b1.length);
socket.receive(datagramPacket1);
String str1 = new String(datagramPacket.getData(),0,datagramPacket.getLength());
System.out.println("客服回复:" + str1);
} catch (Exception e) {
e.printStackTrace();
}
if(ask.equals("再见")) {
break;
}
}while(true);
}
}