IP地址(Internet Protocol):唯一标识网络上的每一台计算机
IP地址的组成:32位,由4个8位二进制数组成
二进制变成十进制方法:位数数值乘以2的位数次方,最大到255
IP地址 = 网络地址 +主机地址
网络地址:标识计算机或网络设备所在的网段
主机地址:标识特定主机或网络设备
IP地址的配置和检测:
查看IP地址,检测网络是否畅通
查看本机的IP地址:ipconfig
测试网络是否通畅:ping (再加上)目标IP地址
【1. 开始里面直接输入cmd;2. 打开dos系统;3. 输入代码】
DNS域名解析:Domain Name System,域名系统
为了好访问,好记忆。通过DNS
网络服务器:
通常指在网络环境下,具有较高计算能力,能够提供用户服务功能的计算机
B/S:浏览器服务器端的服务程序【好处:服务器端自己升级就行了】
C/S:客户端服务器端的服务程序
网络通信协议:
为在网络中不同的计算机之间进行通信而建立的规则、标准或约定的集合
【数据在网络中传输是很复杂的】
HTTP协议:超文本传输协议,互联网应用最广泛的。
FTP协议:文件传输协议。
SMTP协议:简单邮件传输协议。
TCP协议(Transmission Control Protocol 传输控制协议):面向连接的、可靠的、基于字节流的传输通信协议。
UDP协议(User Datagram Protocol 用户数据报协议):无连接的协议,在传输数据之前,客户端和服务器并不建立和维护连接,效率很快。
Socket:
通信链路的端点就被称为“套接字”(英文名Socket);是提供给应用程序的接口
【Socket的底层机制复杂,Java平台提供了一些简单的API,可以更简单有效的使用Socket开发而无需了解底层机制】
Socket分类
- 流式套接字(SOCK_ STREAM)【面向连接、可靠的数据传输服务(对应服务是TCP链接)】
- 数据报式套接字(SOCK_ DGRAM)【无连接服务(数据报似的,基于UDP)更高效】
- 原始式套接字(SOCK_ RAW)
java.net包:
Socket
ServerSocket
DatagramPacket
DatagramSocket
InetAddress
……
基于TCP协议的Socket网络通信:用来实现双向安全连接网络通信
Socket通信模型:进行网络通信时,Socket需要借助数据流来完成数据的传递工作
C:客户端 S:服务器
Socket网络编程一般可以分成如下步骤进行:
Servicer | Client |
1. 创建ServerSocket(…)对象,绑定某一哥端口号 | 1. 创建Socket("…",…)要指定服务器的IP地址,也要指定端口号 |
2. 通过accept()侦听方法,阻塞,等待对方连接 | 发送请求并被accept()侦听到,并建立 连接 |
3. 通过输入、输出流传递信息【客户端是输出输入,服务器是输入输出】 | |
4. 关闭释放资源 |
例1【直接传参数的方法】:
服务器端程序:
public class LogicServicer {
public static void main(String[] args) {
try {
//接收客户端请求
//创建一个Socket
ServerSocket serverSocket = new ServerSocket(5000);
//使用accept()侦听并接收到此ServerSocket的连接
Socket socket = serverSocket.accept();//侦听到之前都是阻塞的
//获得输入流,获得用户的请求
//数据流输入
InputStream is = socket.getInputStream();
// BufferedReader读取字符流
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String info;
// BufferedReader的方法可以一行一行的读
while((info = br.readLine())!=null){
System.out.println("客户端:"+info);
}
//给客户端一个响应
String reply = "欢迎登陆";
//通过输出流将响应发送回给客户端
OutputStream os = socket.getOutputStream();
os.write(reply.getBytes());
//释放相应资源
os.close();
br.close();
is.close();
socket.close();
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
} } }
客户端程序:
public class LogicClient {
public static void main(String[] args) {
//创建一个客户端的Socket
try {
Socket socket = new Socket("localhost",5000);
//通过输出流发送请求
//直接输出数据流
String info = "用户名:樱桃小丸子;密码:123456";
OutputStream os = socket.getOutputStream();
//打散成数据数组
byte[] infos = info.getBytes();
os.write(infos);
//关闭输出流,这是一个半关闭
socket.shutdownOutput();
//通过输入流接收服务器给我的响应
InputStream is = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String reply;
while((reply = br.readLine())!=null){
System.out.println("服务器:"+reply);
}
//释放资源
os.close();
socket.close();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} } }
测试结果:
例2【通过用户对象传参数的方法】:
用户类程序:
public class User implements Serializable{
private String userName;
private String pwd;
public User() {}
public User(String userName, String pwd) {
this.userName = userName;
this.pwd = pwd;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
} }
服务器端程序:
public class LogicServicer {
public static void main(String[] args) {
try {
//接收客户端请求
//创建一个Socket
ServerSocket serverSocket = new ServerSocket(5000);
//使用accept()侦听并接收到此ServerSocket的连接
Socket socket = serverSocket.accept();//侦听到之前都是阻塞的
//获得输入流,获得用户的请求
//将对象反序列化变成输入流
InputStream is = socket.getInputStream();
ObjectInputStream ois = new ObjectInputStream(is);
User user = (User)ois.readObject();
System.out.println("客户端:"+user.getUserName()+"-"+user.getPwd());
//给客户端一个响应
String reply = "欢迎登陆";
//通过输出流将响应发送回给客户端
OutputStream os = socket.getOutputStream();
os.write(reply.getBytes());
//释放相应资源
ois.close();
os.close();
is.close();
socket.close();
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} } }
客户端类:
public class LogicClient {
public static void main(String[] args) {
//创建一个客户端的Socket
try {
Socket socket = new Socket("localhost",5000);
//通过输出流发送请求
//将对象序列化变成输出流
User user = new User("樱桃小丸子","123456");
OutputStream os = socket.getOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(os);
oos.writeObject(user);
//关闭输出流,这是一个半关闭
socket.shutdownOutput();
//通过输入流接收服务器给我的响应
InputStream is = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String reply;
while((reply = br.readLine())!=null){
System.out.println("服务器:"+reply);
}
//释放资源
os.close();
oos.close();
socket.close();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} } }
测试结果:
如何实现多客户请求呢?
- 采用多线程的方式
- 一个专门负责监听的应用主服务程序
- 一个专门负责处理请求的线程程序
例题:
实现服务器和客户端的多线程连接;并且服务器和客户端可以无限对话。
实现思路:
服务器:
一直监听客户请求
一旦监听到有客户请求,立即创建一个线程,开启线程
线程:
接收客户请求,基于客户一个响应(这是之前服务器要做的事)
线程构造方法中去绑定客户端的Socket
客户端:
发送请求到服务器
接收服务器的响应
例如:
线程类:
//接收客户请求,基于客户一个响应(这是之前服务器要做的事)
//线程构造方法中去绑定客户端的Socket
public class LogicThread extends Thread {
private Socket socket;
public LogicThread(Socket socket){
this.socket=socket;
}
//接收客户请求,基于客户一个响应
public void run(){
InputStream is=null;
BufferedReader br=null;
PrintWriter pw=null;
OutputStream os=null;
try{
Scanner input = new Scanner(System.in);
//获得输入流,获得用户的请求
while(true){
is= socket.getInputStream();
br = new BufferedReader(new InputStreamReader(is));
System.out.println(socket.getInetAddress()+"说"+br.readLine());
//给客户端一个响应
//通过输出流将响应发送回给客户端
String reply =input.next();
os = socket.getOutputStream();
pw = new PrintWriter(os);
pw.println(reply);
pw.flush();
}
//释放相应资源
}catch (IOException e) {
e.printStackTrace();
}finally{
try {
pw.close();
os.close();
br.close();
is.close();
} catch (IOException e) {
e.printStackTrace();
} } } }
服务器程序:
//一直监听客户请求
//一旦监听到有客户请求,立即创建一个线程,开启线程
public class LogicServicer {
public static void main(String[] args) {
try {
//接收客户端请求
//创建一个Socket
ServerSocket serverSocket = new ServerSocket(8848);
System.out.println("启动服务器");
//使用accept()侦听并接收到此ServerSocket的连接
//一直监听客户请求
while(true){
Socket socket = serverSocket.accept();//侦听到之前都是阻塞的
System.out.println("已连接");
//创建一个和该客户端响应的线程
LogicThread logicThread = new LogicThread(socket);
logicThread.start();
}
} catch (IOException e) {
e.printStackTrace();
} } }
客户端类:
//发送请求到服务器
//接收服务器的响应
public class LogicClient {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
OutputStream os=null;
PrintWriter pw=null;
InputStream is=null;
BufferedReader br=null;
//创建一个客户端的Socket
try {
Socket socket = new Socket("localhost",8848);
System.out.println("客户端已启动");
//通过输出流发送请求
while(true){
String info =input.next();
os = socket.getOutputStream();
pw = new PrintWriter(os);
pw.println(info);
pw.flush();
//通过输入流接收服务器给我的响应
is = socket.getInputStream();
br = new BufferedReader(new InputStreamReader(is));
System.out.println("服务器:"+br.readLine());
}
//释放资源
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
os.close();
pw.close();
br.close();
is.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} } } }
测试结果:
如何获得客户的IP?
InetAddress(IP地址的封装)
应用实例:
InetAddress ia = socket.getInetAddress();
String ip= ia.getHostAddress();
基于UDP协议的Socket编程:
| TCP | UDP |
是否连接 | 面向连接 | 面向非连接 |
传输可靠性 | 可靠 | 不可靠 |
速度 | 慢 | 快 |
基于UDP协议的Socket网络编程步骤
- 利用 DatagramPacket 对象封装数据报
- 利用 DatagramSocket 发送数据报
- 利用 DatagramSocket 接收数据报
- 利用 DatagramPacket 处理数据报
DatagramPacket类
封装了数据报的数据、数据长度、目标地址和目标端口
DatagramSocket类
接收和发送DatagramPacket对象封装好的数据报
【两个类都在java.net包里】
例子:
礼物—数据(字符串)
包裹—DatagramPacket
快递点—DatagramSocket
寄礼物—send()
收礼物—receive()
基于UDP的Socket通信,服务端:
public class LogicServicer {
public static void main(String[] args) {
byte[] infos = new byte[1024];
DatagramPacket dp = new DatagramPacket(infos,infos.length);
//快递点
DatagramSocket socket=null;
try {
socket = new DatagramSocket(5000);
//在快递点取礼物
socket.receive(dp);
//拆礼物
String info = new String(dp.getData(),0,dp.getData().length);
System.out.println("客户端说:"+info);
//给客户端一个响应
String reply ="一件羽绒服";
byte[] reply2 = reply.getBytes();
//客户端地址
SocketAddress sa = dp.getSocketAddress();
//打开一个包裹
DatagramPacket dp1 = new DatagramPacket(reply2,reply2.length,sa);
//寄出去
socket.send(dp1);
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
socket.close();
} } }
基于UDP的Socket通信,客户端:
public class LogicClient {
public static void main(String[] args) {
//买礼物
String info="心形巧克力!";
byte[] infos = info.getBytes();
//对方地址和邮编(端口号)
InetAddress ia;
//快递点
DatagramSocket socket = null;
try {
ia = InetAddress.getByName("localhost");
//包裹包装礼物
DatagramPacket dp = new DatagramPacket(infos, infos.length, ia, 5000);
socket = new DatagramSocket();
//通过快递点往外寄出礼物
try {
socket.send(dp);
} catch (IOException e) {
e.printStackTrace();
}
//接收服务器的响应
byte[] replys = new byte[1024];
DatagramPacket dp1 = new DatagramPacket(replys,replys.length);
socket.receive(dp1);
String reply = new String(dp1.getData(),0,dp.getData().length);
System.out.println("服务器的响应:"+reply);
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
socket.close();
} } }
测试结果: