Socket编程教程

本文通过四个示例详细介绍了Java中的TCP Socket通信,包括基础的Socket交互、图片拷贝、用户登录以及实现持续通信的方法。同时,还展示了基于UDP协议的简单通信过程,对比了TCP和UDP的区别。通过这些例子,读者可以深入理解Java网络编程的基本操作。
摘要由CSDN通过智能技术生成

一、基础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();
    }
}
  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值