网络编程
IP地址
唯一标识网络上的每一台计算机。相当于现实生活中的家庭住址。两台计算机进行通信,就必须知道双方的IP地址。
IP地址由32位二进制数组成,分为4段8位的二进制数,中间用“.”隔开。如:11000000.10101000.00000001.11001000。
由于二进制数不便于记忆,所以通常ip地址由十进制数表示,即上述例子可表示为192.168.1.200
IP地址的四段8位二进制数是由网络地址和主机地址两部分组成。
网络地址:标识计算机或网络设备所在的网段
主机地址:标识特定主机或网络设备
根据前8位二进制数的取值范围,可以将IP地址分为5类,如图所示:
8位二进制数转为十进制数后,最大值为255,所以不可能出现IP地址的某一段大于255的情况。
如果想要查看本机的IP地址,可以在DOS命令中输入ipconfig,即可查得。
如果想要测试网络是否通常,可以在DOS命令中输入Ping 对方IP地址,若请求超时则网络不通。
DNS域名解析
我们在浏览百度,淘宝等网站时可以发现,我们输入的网址并不是IP地址,而是所谓的域名。我们在输入域名后,会通过域名服务器,找到域名所绑定的IP地址,进而找到该网站的IP地址。
DNS(Domain Name System),域名解析系统,是将网址映射成所绑定的IP地址。
网络服务器
通常指在网络环境下,具有较高计算能力,能够提供用户服务功能的计算机。
常见的网络服务器有邮件服务器、Web服务器等。
比如我们日常使用的QQ中,就有一个QQ邮件,就使用了邮件服务器。而我们浏览的淘宝、京东等网站,就使用了Web服务器。
常用的Web服务器有:Microsoft IIS、APACHE、Apache Tomcat等。
网络通信协议
是为了在网络中不同的计算机之间进行通信而建立的规则、标准或约定的集合。
传统的网络通信协议可以按5层划分:
越往底层,技术难度越高。通常涉及的比较多的是传输层和应用层。
Socket
程序通过Socket向网络发出请求或对请求作出响应。每一种服务都会打开一个Socket并和一个端口绑定。通信链路的端点就被称为“套接字”(英文名Socket),是提供给应用程序的接口。
Socket的底层机制复杂,Java平台提供了一些简单的API,可以更简单有效的使用Socket开发而无需了解底层机制。
Socket分类:
(1)流式套接字(SOCK_STREAM)。即基于TCP协议,是面向连接,可靠的数据传输服务。
(2)数据报式套接字(SOCK_DGRAMM)。基于UDP协议,是无连接服务,更高效,但可能会在传输过程中丢失部分数据,丢包。
(3)原始式套接字(SOCK_RAM)。用的比较少。
基于TCP协议的Socket编程
基于TCP协议的Socket网络通信,是用来实现双向安全连接网络通信。进行网络通信时,Socket需要借助数据流来完成数据的传递工作。
Socket网络编程一般可以分成如下步骤进行:
(1)建立连接(网络编程模型:客户端/服务器(C/S))
(2)打开Socket关联的输入输出流
(3)数据流中读写信息
(4)关闭所有的数据流和Socket
如果要实现多线程处理多请求,需要采用多线程的方式:
一个专门负责监听的应用主服务程序(死循环操作)
一个专门负责处理请求的线程程序
步骤如下:
(1)创建服务器端线程类,run()方法实现对一个请求的响应处理。
(2)修改服务器端代码,实现循环监听状态
(3)服务器端每监听到一个请求,创建一个处理线程
//User类
import java.io.Serializable;
public class User implements Serializable{
private String name;
private String pwd;
public User() {
}
public User(String name, String pwd) {
this.name = name;
this.pwd = pwd;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
}
//客户端
import java.io.*;
import java.net.*;
import java.util.*;
public class Sockets {
public static void main(String[] args) {
Scanner scan =new Scanner(System.in);
Socket socket=null;
OutputStream os =null;
ObjectOutputStream oos=null;
InputStream is =null;
InputStreamReader isr=null;
BufferedReader br =null;
try {
socket =new Socket("localhost",8888);
os =socket.getOutputStream();
User user =new User();
System.out.print("请输入用户名:");
user.setName(scan.next());
System.out.print("请输入密码:");
user.setPwd(scan.next());
oos=new ObjectOutputStream(os);
oos.writeObject(user);
socket.shutdownOutput();
is =socket.getInputStream();
isr =new InputStreamReader(is);
br =new BufferedReader(isr);
System.out.println(br.readLine());
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
if(br!=null) {
br.close();
}
if(isr!=null) {
isr.close();
}
if(is!=null) {
is.close();
}
if(oos!=null) {
oos.close();
}
if(os!=null) {
os.close();
}
if(socket!=null) {
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
//服务器端线程类
import java.io.*;
import java.net.*;
public class LoginThread extends Thread{
private Socket socket;
public LoginThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
InputStream is =null;
InputStreamReader isr =null;
ObjectInputStream ois=null;
OutputStream os =null;
Writer osw =null;
try {
is = socket.getInputStream();
isr = new InputStreamReader(is);
ois =new ObjectInputStream(is);
User user =(User)ois.readObject();
os=socket.getOutputStream();
osw=new OutputStreamWriter(os);
if(user.getName().equals("admin")&&user.getPwd().equals("123456")) {
osw.write("登录成功!");
}else {
osw.write("用户名或密码不正确!");
}
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}finally {
try {
if(osw!=null) {
osw.close();
}
if(os!=null) {
os.close();
}
if(ois!=null) {
ois.close();
}
if(isr!=null) {
isr.close();
}
if(is!=null) {
is.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
//服务器
import java.io.IOException;
import java.net.*;
public class servers {
public static void main(String[] args) {
ServerSocket serverSocket=null;
Socket socket=null;
try {
serverSocket =new ServerSocket(8888);
while(true) {
socket =serverSocket.accept();
LoginThread thread =new LoginThread(socket);
thread.start();
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
if(socket!=null) {
socket.close();
}
if(serverSocket!=null) {
serverSocket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
基于UDP协议的Socket编程
TCP协议与UDP协议的比较:
TCP | UDP | |
---|---|---|
是否连接 | 面向连接 | 面向非连接 |
传输可靠性 | 可靠 | 不可靠 |
速度 | 慢 | 快 |
TCP协议相当于需要一个指定的服务器,所有客户端向服务器发送请求。而UDP协议没有指定的服务器,每个客户端都可以相当于一个服务器,无需连接也能获取数据,但可能会在传输过程中丢失部分数据。通常在一些视频会议、聊天等情况下可以使用UDP协议。
基于UDP协议的Socket编程步骤如下:
(1)利用DatagramPacket对象封装数据包
(2)利用DatagramSocket发送数据包
(3)利用DatagramSocket接收数据包
(4)利用DatagramPacket处理数据包