一、基础socket演示
服务端
package Io.com.lian.net;
import java.io.DataInputStream;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args) throws Exception {
//服务端需要使用ServerSocket来开放本地的端口
ServerSocket serverSocket = new ServerSocket(10086);
//需要接受客户端传输过来的数据,需要定义socket对象
Socket server = serverSocket.accept();
//通过server获取输入流对象
InputStream inputStream = server.getInputStream();
DataInputStream dataInputStream = new DataInputStream(inputStream);
String s = dataInputStream.readUTF();
System.out.println(s);
//关闭流
dataInputStream.close();
inputStream.close();
server.close();
serverSocket.close();
}
}
客户端
package Io.com.lian.net;
import java.io.DataOutputStream;
import java.io.OutputStream;
import java.net.Socket;
/**
* 客户端向服务端发送数据
*/
public class Client {
public static void main(String[] args) throws Exception {
//创建Socket对象,其实是开启实现io的虚拟接口,此接口不是java中的接口,而是类似于网线的插槽
//需要指定数据接收方的ip地址和端口号
Socket client = new Socket("localhost",10086);
//获取输出流对象,想服务端发送数据
OutputStream outputStream = client.getOutputStream();
DataOutputStream dataOutputStream = new DataOutputStream(outputStream);
dataOutputStream.writeUTF("hello");
//关闭流
dataOutputStream.close();
outputStream.close();
client.close();
}
}
二、图片拷贝案例演示
客户端
package Io.com.lian.socket;
import java.io.*;
import java.net.Socket;
/**
* 需求:将本地图片上传到服务器
* 网络通信必须有协议,tcp协议
* 通信是双向的,socket接口,用来获取输入和输出流
*/
public class Client {
public static void main(String[] args) throws Exception {
File file = new File("D:\\dog.jpg");
//创建io流,将图片传入需要用文件输入流
FileInputStream fileInputStream = new FileInputStream(file);
//创建socket客户端
Socket socket = new Socket("127.0.0.1", 1000);
OutputStream outputStream = socket.getOutputStream();
//客户端将数据输出到Socket服务器
int len = 0;
while ((len = fileInputStream.read()) != -1) {
outputStream.write(len);
}
//输出流后要写停止流命令
socket.shutdownOutput();
//接受服务端的响应
InputStream inputStream = socket.getInputStream();
DataInputStream dataInputStream = new DataInputStream(inputStream);
dataInputStream.read();
//传输完要关闭流
dataInputStream.close();
outputStream.close();
socket.close();
fileInputStream.close();
}
}
服务端
package Io.com.lian.socket;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args) throws Exception {
//创建socket服务器
ServerSocket serverSocket = new ServerSocket(1000);
//等待客户端来连接,连接前阻塞
Socket socket = serverSocket.accept();
//有客户端连接服务器后,获取客户端输入到服务器的信息
InputStream inputStream = socket.getInputStream();
//创建文件输出流对象
File file = new File("D:\\niu.jpg");
FileOutputStream fileOutputStream = new FileOutputStream(file);
//服务端将从客户端接收过来的输入流数据,传入到新创建的文件输出流,再传出到具体路径下的file中
int len = 0;
while ((len = inputStream.read()) != -1){
fileOutputStream.write(len);
}
//服务端接收完数据后要下命令停止
socket.shutdownInput();
//上传图片结束后给予响应
OutputStream outputStream = socket.getOutputStream();
DataOutputStream dataOutputStream = new DataOutputStream(outputStream);
dataOutputStream.write("success".getBytes());
//关闭流
dataOutputStream.close();
fileOutputStream.close();
inputStream.close();
socket.close();
serverSocket.close();
}
}
三、登录案例演示
需求:实现用户登录,客户端序列化对象,服务端反序列化对象
配置实体类实现序列化接口自动生成SerializeUUID
实体类
package Io.com.lian.socket.demo;
import java.io.Serializable;
/**
* 实体类实现序列化接口
* 因为要确保序列化和反序列化的是同一个对象,所以要生成一个 序列化的UUID的值
* 自动生成 序列化的uuid值
*/
public class User implements Serializable {
private static final long serialVersionUID = -487300481102457700L;
private String username;
private String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User{" +
"username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}
客户端
package Io.com.lian.socket.demo;
import java.io.DataInputStream;
import java.io.InputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;
public class LoginClient {
public static void main(String[] args) throws Exception {
Socket socket = new Socket("127.0.0.1",2000);
//完成登录功能,需要传输一个user对象
User user = getUser();
//传输对象需要 ObjectOutputStream
OutputStream outputStream = socket.getOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
objectOutputStream.writeObject(user);
//调用 shutdown 方法告诉对方传输完成
socket.shutdownOutput();
//接收服务端的消息
InputStream inputStream = socket.getInputStream();
DataInputStream dataInputStream = new DataInputStream(inputStream);
String str = dataInputStream.readUTF();
System.out.println(str);
socket.shutdownInput();
//关闭流
dataInputStream.close();
objectOutputStream.close();
outputStream.close();
socket.close();
}
private static User getUser() {
Scanner scanner = new Scanner(System.in);
System.out.println("please input username");
String username = scanner.nextLine();
System.out.println("please input password");
String password = scanner.nextLine();
User user = new User(username, password);
return user;
}
}
服务端
package Io.com.lian.socket.demo;
import java.io.DataOutputStream;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class LoginServer {
public static void main(String[] args) throws Exception {
ServerSocket serverSocket = new ServerSocket(2000);
Socket socket = serverSocket.accept();
//获取输入流对象
InputStream inputStream = socket.getInputStream();
//需要用处理流将节点流包装起来
ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
User user = (User) objectInputStream.readObject();
String str ="";
if ("pi".equals(user.getUsername()) && "123".equals(user.getPassword())){
str = "login success";
}else {
str = "login fail";
}
//截断输入流
socket.shutdownInput();
//服务端响应客户端
OutputStream outputStream = socket.getOutputStream();
DataOutputStream dataOutputStream = new DataOutputStream(outputStream);
dataOutputStream.writeUTF(str);
socket.shutdownOutput();
//关闭流
objectInputStream.close();
inputStream.close();
socket.close();
serverSocket.close();
}
}
如何解决客户端的持续通信呢?
四、实现持续通信
while方法
package Io.com.lian.socket.demo2;
import java.io.DataOutputStream;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class LoginServer {
public static void main(String[] args) throws Exception {
ServerSocket serverSocket = new ServerSocket(3000);
while (true){
Socket socket = serverSocket.accept();
//获取输入流对象
InputStream inputStream = socket.getInputStream();
//需要用处理流将节点流包装起来
ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
User user = (User) objectInputStream.readObject();
String str ="";
if ("pi".equals(user.getUsername()) && "123".equals(user.getPassword())){
str = "login success";
}else {
str = "login fail";
}
//截断输入流
socket.shutdownInput();
//服务端响应客户端
OutputStream outputStream = socket.getOutputStream();
DataOutputStream dataOutputStream = new DataOutputStream(outputStream);
dataOutputStream.writeUTF(str);
socket.shutdownOutput();
//关闭流
objectInputStream.close();
inputStream.close();
socket.close();
}
// serverSocket.close();
}
}
多线程方法
第1步:实现Runnable接口
package Io.com.lian.socket.demo2;
import java.io.*;
import java.net.Socket;
public class LoginThread implements Runnable {
private Socket socket;
public LoginThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
InputStream inputStream = null;
ObjectInputStream objectInputStream = null;
try {
inputStream = socket.getInputStream();
objectInputStream = new ObjectInputStream(inputStream);
User user = (User) objectInputStream.readObject();
String str = "";
if ("pi".equals(user.getUsername()) && "123".equals(user.getPassword())){
str = "login success";
} else {
str = "login fail";
}
socket.shutdownInput();
//响应客户端
OutputStream outputStream = socket.getOutputStream();
DataOutputStream dataOutputStream = new DataOutputStream(outputStream);
dataOutputStream.writeUTF(str);
socket.shutdownOutput();
}catch (Exception e){
e.printStackTrace();
}finally {
try {
socket.close();
inputStream.close();
objectInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
第2步:服务端配置while方法
package Io.com.lian.socket.demo2;
import java.net.ServerSocket;
import java.net.Socket;
public class LoginThreadServer {
public static void main(String[] args) throws Exception {
ServerSocket serverSocket = new ServerSocket(3000);
while (true){
Socket socket = serverSocket.accept();
LoginThread loginThread = new LoginThread(socket);
new Thread(loginThread).start();
}
// serverSocket.close();
}
}
五、UDP网络编程
基于tcp和udp协议的socket编程区别
tcp协议的socket通信双发需要建立连接,udp不需要建立连接
tcp建立连接时双方存在主次之分,udp通信双方完全平等
客户端
package Io.com.lian.socket.demo3;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;
public class UdpClient {
public static void main(String[] args) throws Exception {
//创建udp通信的socket
DatagramSocket datagramSocket = new DatagramSocket(4000);
Scanner scanner = new Scanner(System.in);
String str = scanner.nextLine();
DatagramPacket datagramPacket = new DatagramPacket(str.getBytes(), str.length(), InetAddress.getByName("localhost"), 4001);
datagramSocket.send(datagramPacket);
datagramSocket.close();
}
}
服务端
package Io.com.lian.socket.demo3;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class UdpServer {
public static void main(String[] args) throws Exception {
DatagramSocket datagramSocket = new DatagramSocket(4001);
byte[] buf = new byte[1024];
DatagramPacket datagramPacket = new DatagramPacket(buf,buf.length);
datagramSocket.receive(datagramPacket);
System.out.println(new String(datagramPacket.getData(),0,datagramPacket.getLength()));
datagramSocket.close();
}
}