1、什么是网络编程:
网络编程就是通过写的一段程序代码在多台计算机中相互交换数据
2、网络编程三要素:
ip地址:想让网络中的计算机相互通信,必须为每台计算机都指定一个标识符,来指定接收数据,ip就是这个标识符,也是设备的标识。
端口:网络通信本质上是两个应用程序的通信,计算机中有很多的应用程序,可以说ip地址是两台计算机通信的标识符,那么端口就是应用程序的标识符。
通信协议:是计算机相互通信需要遵守的规则,它对传输速率,传输格式等一些有具体的规定,只有双方都遵守规定才可以进行数据交换。常用的协议有UDP和TCP协议
3、InetAdress类的使用
这个类没有构造方法(所以不能直接使用new关键字)但是可以用静态的方法(InetAddress.getByName(“String”);String 可以是主机名或者是主机IP地址)来获得。通过InterAddress.getHostName()获取当前主机的名字;通过InterAddress.getHostAddress()获取当前主机IP地址,都是通过文本形式返回的。
public static void main(String[] args) throws UnknownHostException {
InetAddress inetAddress =InetAddress.getByName("192.168.3.3");//通过静态方法getByName获得
String name=inetAddress.getHostName();//通过文本形式显示当前主机名
String address=inetAddress.getHostAddress();//通过文本形式获得当前主机IP地址
System.out.println(name);
System.out.println(address);
}
什么是UDP协议:UDP是用户数据报协议的缩写,一个无连接的协议。提供了应用程序之间要发送的数据的数据包。
UDP发送数据步骤:
1、创建一个socket对象,
2、创建数据包,并把数据打包
3、调用DatagramSocket对象发送数据
4、关闭发送端
//1、创建一个socket对象
DatagramSocket ds = new DatagramSocket();
//2、创建数据包,并把数据打包
byte [] bys="hello,UDP".getBytes();
//创建一个DatagramPack数据报包对象
DatagramPacket dp = new DatagramPacket(bys,bys.length,InetAddress.getByName("192.168.3.3"),10086);
// 3、调用DatagramSocket对象发送数据
ds.send(dp);
// 4、关闭发送端
ds.close();
UDP接收数据步骤:
1、创建一个socket对象,
2、创建数据包,并把数据打包
3、调用DatagramSocket对象中的方法接收数据
4、解析数据,并在控制台显示
4、关闭接收端
// UDP接收数据步骤:
public static void main(String[] args) throws IOException {
//1、创建一个DatagramSocket对象
DatagramSocket ds = new DatagramSocket(10086);
//2、创建数据包,并把数据打包
byte[] bys=new byte[1024];
DatagramPacket dp = new DatagramPacket(bys, bys.length);
//3、调用DatagramSocket对象中的方法接收数据
ds.receive(dp);
//4、解析数据,并在控制台显示
System.out.println("数据是:"+new String(dp.getData(),0,bys.length));
//4、关闭接收端
ds.close();
}
什么是TCP协议:TCP是一种可靠的网络协议,它在通信的两端都建立了socker对象,从而在通信的两端形成网络虚拟链路。Java为TCP协议的通信提供了很好的封装,使用socket对象表示通信两端的端口,并通过socker对象产生的IO流来进行网络通信,Java为客户端提供Socket类,为服务端提供ServerSocket类
TCP协议发送数据步骤:
1、创建Socket对象
2、获取输出流,写数据
3、释放资源
public static void main(String[] args) throws IOException {
Socket socket = new Socket("192.168.3.3",10000);//创建Socket对象,指定Host和port
OutputStream outputStream = socket.getOutputStream();//获取输出流,写数据
outputStream.write("hello,tcp".getBytes());//写数据
socket.close();//释放资源
}
TCP协议接收数据步骤:
1、创建ServerSocket对象
2、监听客户端连接,返回一个socket对象
2、获取输入流,读数据,并显示在控制台上
3、释放资源
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(10000);//创建ServerSocket对象,指定port
Socket ss = serverSocket.accept();//监听客户端的连接
InputStream is = ss.getInputStream();//获取输入流,读数据
byte[] bys=new byte[1024];
System.out.println("数据是:"+new String(bys,0,is.read(bys)));//解析数据,并显示在控制台上
serverSocket.close();//释放资源
}
TCP通信练习:
1、客户端获取键盘输入,886作为结束 服务端接受客户端输入。
public class test05_Client {
public static void main(String[] args) throws IOException {
//创建Socket对象
Socket s = new Socket("192.168.3.3",10000);
//获取输出流对象
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));//从键盘录入数据
//封装输出流对象
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
String line;
while ((line=br.readLine())!=null){
if("886".equals(line)){
break;
}
bw.write(line);//将指定的字节写入缓冲的输出流。
bw.newLine();//写一个行分隔符。
bw.flush();//刷新缓冲输出流。
}
s.close();
}
}
public class test05_Server {
public static void main(String[] args) throws IOException {
//创建一个ServerSocket对象
ServerSocket ss = new ServerSocket(10000);
//监听
Socket s = ss.accept();
//获取输入流
BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
//解析数据,显示在控制台上
String line;
while ((line=br.readLine())!=null){//确保获取内容不为空
System.out.println(line);
}
ss.close();
}
}
2、客户端获取键盘输入,886作为结束 服务端接受客户端输入,存储到文本中。
因为客户端和1一致就不贴代码了
public class test05_Server {
public static void main(String[] args) throws IOException {
//创建一个ServerSocket对象
ServerSocket ss = new ServerSocket(10000);
//监听
Socket s = ss.accept();
//获取输入流
BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
String line;
BufferedWriter bw = new BufferedWriter(new FileWriter("text.txt",true));//写内容到文件中,追加方式写进
while ((line=br.readLine())!=null){//确保获取内容不为空
bw.append(line);
bw.newLine();
bw.flush();
}
bw.close();
ss.close();
}
}
3、客户端获取文本文件内容获得服务端给出的反馈 服务端接受客户端输入,存储到文本中,给客户端一个反馈。
Socket s = new Socket("192.168.3.3",10000);
BufferedReader br = new BufferedReader(new FileReader("textClient.txt"));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
String line;
while ((line=br.readLine())!=null){
bw.write(line);
bw.newLine();
bw.flush();
}
//void shutdownOutput()
//Disables the output stream for this socket.
s.shutdownOutput();//Disables the output stream for this socket.
//接收反馈
BufferedReader brClient = new BufferedReader(new InputStreamReader(s.getInputStream()));
System.out.println("服务器的反馈"+brClient.readLine());
br.close();
s.close();
在写服务器反馈遇到的问题是,客户端在读取完文本文件后开始获取服务端的反馈,但是服务器端仍然在等待客户端发送数据,没有结束等待。解决办法:在客户端读取文本文件结束后,调用shutdownOutput()方法来告诉服务端已经停止读取了。也可以自定义一个结束标记但是不推荐使用
public static void main(String[] args) throws IOException {
//创建一个ServerSocket对象
ServerSocket ss = new ServerSocket(10000);
//监听
Socket s = ss.accept();
//获取输入流
BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
String line;
BufferedWriter bw = new BufferedWriter(new FileWriter("textServer.txt",true));//写内容到文件中,追加方式写进
while ((line=br.readLine())!=null){//确保获取内容不为空
bw.append(line);
bw.newLine();
bw.flush();
}
//给出反馈
BufferedWriter bwServer = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
bwServer.write("文件上传成功");
bwServer.newLine();
bwServer.flush();
bw.close();
ss.close();
}
4、客户端获取文本文件内容 服务端接受客户端输入,存储到文本中,代码用线程封装一个客户端一个线程。
ServerSocket ss = new ServerSocket(10000);
Socket s = ss.accept();
//为每一个客户端开启一个线程
new Thread(new ServerThread(s)).start();
class ServerThread implements Runnable {
private Socket s;
public ServerThread(Socket s) {
this.s=s;
}
@Override
public void run() {
try {
int count=0;
BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
//避免文件名重复
File file = new File("text[" + count + "].txt");
String line;
while (file.exists()){
count++;
file = new File("text[" + count + "].txt");
}
BufferedWriter bw = new BufferedWriter(new FileWriter(file));
while ((line=br.readLine())!=null){
bw.write(line);
bw.newLine();
bw.flush();
}
// 给出反馈
BufferedWriter bwServer = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
bwServer.write("文件上传成功");
bwServer.newLine();
bwServer.flush();
s.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
实现客户端传数据给服务端,服务端判断数据是否正确并告知客户端
(实现账号密码登录功能并加入多线程)
package com.socket.socket2;
import java.io.*;
import java.net.Socket;
public class Client {
public static void main(String[] args) {
/*
* 客户端
* */
Socket socket = null;
boolean flag;
try {
socket = new Socket("localHost", 9000);
//获取用户输入
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
//向服务器反馈数据
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
//接受服务端返溃数据
DataInputStream dis = new DataInputStream(socket.getInputStream());
while (true) {
System.out.println("用户名:");
String name = br.readLine();
System.out.println("密码:");
String password = br.readLine();
//封装数据
User user = new User(name, password);
oos.writeObject(user);
//接受服务器返溃数据
flag = dis.readBoolean();
//如果成功则返回true
if (flag) {
System.out.println("登陆成功");
break;
} else {
System.out.println("用户名或密码错误");
}
}
} catch (Exception e) {
e.printStackTrace();
}finally {
if(socket !=null){
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
服务端
package com.socket.socket2;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args) {
/*
* 服务端
* */
ServerSocket ss = null;
Socket socket = null;
try {
ss = new ServerSocket(9000);
while (true) {
socket = ss.accept();
System.out.println(socket.getInetAddress().getHostName() + "连接成功");
// 实现多线程
ServerRunnable serverRunnable = new ServerRunnable(socket);
new Thread(serverRunnable).start();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
多线程
package com.socket.socket2;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.net.Socket;
public class ServerRunnable implements Runnable {
private Socket socket;
public ServerRunnable() {
}
public ServerRunnable(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
boolean flag = false;
//获取客户端发的数据
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
while (true) {
User user = (User) ois.readObject();
if (user.getName().equals("admin") && user.getPassword().equals("abc")) {
System.out.println("登陆成功");
flag = true;
} else if (user.getName().equals("user") && user.getPassword().equals("123")) {
System.out.println("登陆成功");
flag = true;
} else {
System.out.println("登陆失败");
}
dos.writeBoolean(flag);
if (flag) {
break;
}
else {
System.out.println("失败");
}
}
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
用户类
package com.socket.socket2;
import java.io.Serializable;
import java.util.Objects;
public class User implements Serializable {
private String name;
private String password;
public static final long serialVersionUID=1L;
public User() {
}
public User(String name, String password) {
this.name = name;
this.password = password;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", password='" + password + '\'' +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
User user = (User) o;
return Objects.equals(name, user.name) && Objects.equals(password, user.password);
}
@Override
public int hashCode() {
return Objects.hash(name, password);
}
}