网络编程
IP地址
IP地址 = 网络地址 +主机地址
网络地址:表示计算机或网络设备所在的网段
主机地址:表示特定主机或网络设备
查看IP地址,检测网络是否通畅
查看本机的IP地址
ipconfig
测试网络是否畅通
ping 目标IP地址
DNS:Domain Name System,域名系统。用于域名与IP地址的相互转换
网络服务器:通常指在网络环境下,具有较高计算能力,能够提供用户服务功能的计算机
B/S:Browser/Server:浏览器/服务器模式
C/S:Client/Server,客户端/服务器模式
网络通信协议
协议:为了在网络中不同的计算机之间进行通信而建立的规则、标准或约定的集合
TCP/IP五层
物理层
数据链路层
网络层
传输层
应用层
Socket
Socket:通信链路的端点就被称为"套接字"(英文名Socket)
分类
流式套接字(SOCK_STREAM)
面向连接、可靠的数据传输服务
数据报式套接字(SOCK_DGRAM)
无连接服务
原始套接字(SOCK_RAW)
Socket的底层机制复杂,Java平台提供了一些简单的API,可以更简单有效的使用Socket开发而无需了解底层机制
java.net包
Socket
ServerSocket
DatagramPacket
DatagramSocket
InteAddress
…
基于TCP协议的Socket网络通信
用来实现双向安全连接网络通信
Socket通信模型
进行网络通信时,Socket需要借助数据流来完成数据的传递工作
Socket网络编程步骤
STEP 1:建立连接:网络编程模型:客户端/服务器(C/S)
STEP 2:打开Socket关联的输入输出流
STEP 3:数据流中读写信息
STEP 4:关闭所有的数据流和Socket
传递字符串
Socket编程关键实现
1.ServerSocket、Socket对象创建
2.ServerSocket.accept()监听接受请求,建立连接
3.输入输出流创建
传递对象
网络通信中对象的的传递借助序列化实现
ObjectOutputStream oos = new ObjectOutputStream(...);
oos.writeObject(...);
ObjectInputStream ois = new ObjectInputStream(...);
Object = ois.readObject();
实现多客户请求
1.采用多线程的方式
2.一个专门负责监听的应用主服务程序
3.一个专门负责处理请求的线程程序
多客户端与服务器网络通信,可借助多线程实现
客户端
发送请求,接收响应
服务器
循环监听用户请求
一旦监听到请求,创建并开启线程
线程
接收并处理客户请求
获取客户端IP信息
java.net.InetAddress
getHostAddress():返回文本显示的IP地址字符串
getHostName():获取此IP地址的主机名
案例
案例一
模拟用户登录的功能
实现客户发送登陆用户信息,服务器端显示登陆信并响应给客户端登陆成功
-测试类
package hw1;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
public class Test {
public static void main(String[] args) {
try {
Socket socket = new Socket("localhost",8888);
OutputStream os = socket.getOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(os);
User user = new User("admin","123456");
oos.writeObject(user);
//String showInfo = "用户名: admin;密码:123456";
//os.write(showInfo.getBytes());
socket.shutdownOutput();
InputStream is =socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String reply;
while((reply = br.readLine())!=null) {
System.out.println("服务器响应: "+reply);
}
br.close();
is.close();
oos.close();
os.close();
socket.close();
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
-User类
package hw1;
import java.io.Serializable;
public class User implements Serializable{
private String userName;
private String userPwd;
public User() {
super();
// TODO Auto-generated constructor stub
}
public User(String userName, String userPwd) {
super();
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;
}
}
-线程类
package hw1;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
/**
* 服务器
* @author admin
*
*/
public class LoginServer {
public static void main(String[] args) {
// TODO Auto-generated method stub
try {
ServerSocket serverSocket = new ServerSocket(8888);
Socket socket = serverSocket.accept();
InputStream is = socket.getInputStream();
ObjectInputStream ois = new ObjectInputStream(is);
User user = (User)ois.readObject();
System.out.println("客户端: "+user.getUserName()+"-"+user.getUserPwd());
OutputStream os = socket.getOutputStream();
// String info;
// while((info = br.readLine())!= null) {
// System.out.println("客户端: "+info);
// }
String reply = "欢迎登陆";
os.write(reply.getBytes());
os.close();
ois.close();
is.close();
socket.close();
serverSocket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
案例二
需求说明:升级前一个上机内容,实现多客户端用户登录
分析:
1.创建服务器端线程类,run()方法中实现对一个请求的相应处理
2.修改服务器端代码,实现循环监听状态
3.服务器端没见听到一个请求,创建一个处理线程
-线程类
package homework2;
/**
* 服务器端的线程类
*/
import java.io.*;
import java.net.*;
public class LoginThread extends Thread{
private Socket socket; //端口作为属性,便于每个线程根据接收到的客户端端口来操作run()方法
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 {
//创建对应客户端socket的输入流,返回InputStream类型
is = socket.getInputStream();
//ObjectInputStream需要一个Reader类型参数,
//而InputStreamReader刚好能连接上is(对接客户端)
isr = new InputStreamReader(is);
//用ObjectInputStream来接收对象数据
ois =new ObjectInputStream(is);
//把读到的对象赋给新的变量user
User user =(User)ois.readObject();
//获得客户端对应的socket的输出流,给客户端反馈信息,返回OutputStream类型
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();
}
}
}
}
-服务器端
package homework2;
/**
* 服务器端
*/
import java.io.IOException;
import java.net.*;
public class servers {
public static void main(String[] args) {
ServerSocket serverSocket=null;
Socket socket=null;
try {
//创建服务器端口的对象,端口号8888,与客户端端口号对应
serverSocket =new ServerSocket(8888);
//死循环,让服务器能一直监听客户端发送信息,不需要每次都重新运行服务器
while(true) {
//等待接收每一个客户端发来的信息,返回一个和客户端对应的socket
socket =serverSocket.accept();
//每接收到一个客户端的信息,创建一个线程来处理对应客户端,
//把对应客户端的端口socket传到对应线程对象的socket属性中去,在线程类的run()中用
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();
}
}
}
}
-Socket
package homework2;
/**
* 客户端
*/
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 端口号8888
socket =new Socket("localhost",8888);
//获得客户端端口的输出流对象(返回值是OutputStream类型)
os =socket.getOutputStream();
//创建一个User对象,用来存一组用户名密码信息
User user =new User();
System.out.print("请输入用户名:");
user.setName(scan.next());
System.out.print("请输入密码:");
user.setPwd(scan.next());
//输出对象数据的输出流对象(序列化)ObjectOutputStream类型
oos=new ObjectOutputStream(os);
//用序列化把user对象输出到服务器
oos.writeObject(user);
//关闭客户端端口的输出流,不然后面读不到服务器的反馈
socket.shutdownOutput();
//获得端口的输入流对象,用来读取服务器反馈信息,返回InputStream类型
is =socket.getInputStream();
//创建字符输入流对象
isr =new InputStreamReader(is);
//用能整行读取的BufferReader输入流
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();
}
}
}
}
-User
package homework2;
/**
* 登录账号信息类
*/
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;
}
}
{
e.printStackTrace();
}
}
}
}
-User
```JAVA
package homework2;
/**
* 登录账号信息类
*/
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;
}
}