Java网络通信实验小记二:Socket编程

Socket编程——TCP&UDP


一、Socket套接字概述
  • 网络上具有唯一标识符的IP地址和端口号组合在一起才能构成唯一能识别的标识符套接字。
  • 通信的两端都有Socket。
  • 网络通信其实就是Socket通信。
  • 数据在两个Socket之间通过IO流传输。
  • Socket在应用程序中创建,通过一种绑定机制与驱动程序建立关系,告诉自己IP和端口号

可以把主机当做港口,Socket就是码头,端口号就是码头号,不同的应用程序使用不同的端口,码头之间通过IO流传输Data,如图:
在这里插入图片描述

二、Java进行TCP通信

1.流程:

  • 连接阶段
    服务端——创建ServerSocket对象(指定port),监听并等待客户端连接。
    客户端——创建Socket对象(指定服务端ip,port),与服务端取得连接。
    服务端——连接成功时serverSocket的accept()方法返回一个Socket对象。
  • 传输阶段
    服务端:通过PrintWriter获取socket套接字的输出流,BufferedReader获取socket套接字的输入流。
    客户端:通过PrintWriter获取socket套接字的输出流,BufferedReader获取socket套接字的输入流。

PrintWriter使用方法:

PrintWriter out = new PrintWriter(socket.getOutputStream(), true);

BufferedReader使用方法:

BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));

2.代码
(1)TcpServer.java

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
/**
 * 服务端代码
 */
public class TcpServer {
    public static void main(String[] args) {
        try {
            //创建ServerSocket监听器
            ServerSocket serverSocket = new ServerSocket(1081);
            //阻塞,等待客户端连接。accept()方法返回一个Socket类
            Socket socket = serverSocket.accept();
            //通过PrintWriter获取客socket套接字的输出流
            PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
            //通过BufferedReader获取socket套接字的输入流
            BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            //从客户端读取数据
            String name=in.readLine(),id=in.readLine(),userIn;
            System.out.println("收到客户端消息:姓名:"+name+",学号:"+id);
            //发送数据到客户端
            out.println(name+"同学,我已接受到你的申请");
            while ((userIn = in.readLine()) != null) {
                System.out.println("收到客户端消息:" + userIn);
                //发回客户端
                switch(userIn)
                {
                    case "你好骚啊" : out.println("你也是");break;
                    case "我王境泽就是饿死" : out.println("真香");break;
                    case "窝窝头,一块钱四个" : out.println("嘿嘿!");break;
                    case "鸡你太美" : out.println("全民制作人们大家好,我是练习时长两年半的蔡徐坤,喜欢唱跳rap篮球,music~");break;
                    case "music" : out.println("鸡你太美~~");break;
                    case "听我的" : out.println("我不要你觉得,我要我觉得");break;
                    case "" : out.println("哈哈哈哈哈。你说啥?");break;
                    default : out.println("?");break;
                }
            }
            //关闭监听器
            serverSocket.close();
            //关闭socket套接字
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

(2)UdpClient.java

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;
/**
 * 客户端代码
 */
public class TcpClient {
    public static void main(String[] args) {
        String hostname = "192.168.131.131";//127.0.0.1
        //socket端口
        int port = 1081;
        Scanner userIn = new Scanner(System.in);
        try {
            //创建socket套接字
            Socket socket = new Socket(hostname, port);
            //使用PrintWriter获取socket输出流将数据发送到服务器
            PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
            //使用BufferedReader获取socket输入流读取服务器返回的数据
            BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            System.out.println("请输入你的姓名和学号:");
            String name=userIn.next(),id=userIn.next(),userInput;
            System.out.println("客户端已发送:姓名:"+name+",学号:"+id);
            //向服务端发送数据
            out.println(name);out.println(id);
            //从服务端获取数据
            System.out.println("收到服务端回应:" + in.readLine());
            //当用户输入exit时退出
            System.out.println("请发送消息(输入exit退出):");
            while (!"exit".equals(userInput = userIn.nextLine())) {
                out.println(userInput);
                System.out.println("收到服务端回应:" + in.readLine());
                System.out.print("请发送消息(输入exit退出):");
            }
            //关闭socket
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

3.实验结果
先运行TcpServer,再运行TcpClient。
(1)实现两台Linux虚拟机的通信。如图:
在这里插入图片描述
(2)实现Windows和虚拟机的通信
这里面有一个很烦人的中文乱码问题,捣鼓很久后成功解决:
因为windows系统使用的是GBK编码,Linux系统使用的是UTF-8编码,所以服务端BufferedReader要设成GBK,客户端要设成UTF-8!!!!!
即:服务端

BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream(),"GBK"));

客户端

BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream(),"UTF-8"));

其他的都不变。结果如图:
在这里插入图片描述

三、Java进行UDP通信

1.流程:
(UDP不分服务端和客户端,因此以接收端和发送端称呼之)

  • 接收端——创建DatagramSocket对象(指定port)。创建DatagramPacket对象(空箱,指定空buffer和buffer大小)。使用socket的recieve方法等待数据的接收。
  • 发送端——创建DatagramSocket对象(不指定port)。创建DatagramPacket对象(数据装箱,指定buffer、buffer大小以及要送去的port的端口号)

我画了张图来形象的表示UDP的发送和接收过程:
在这里插入图片描述
2.代码
(1)UdpReceiver.java

import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class UdpReceiver
{
    public static void main(String[] args)
    {
        try {
            //创建接收端监听socket,需要指定监听端口,请注意,该端口务必与发送端设定 的目标端口一致
            DatagramSocket socket = new DatagramSocket(1081);
            //指定存放接收数据的缓存
            byte[] buffer = new byte[1024];
            //生成用来接收的DatagramPacket,这里与发送端不同,无需关系IP和端口
            DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
            //调用receive方法接收数据,需要注意,该方法是一个阻塞型的方法,没有接收到数据包之前会一直等待
            socket.receive(packet);
            //获取数据内容
            System.out.println("数据内容:"+new String(packet.getData(),0,packet.getLength()));
            //获取数据长度
            System.out.println("数据长度:"+packet.getLength());
            //获取端口号
            System.out.println("对端端口号是:"+packet.getPort());
            socket.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

(2)UdpSender.java

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class UdpSender
{
    public static void main(String[] args)
    {
        try{
            //创建发送端Socket,因为发送端不关心发送端口,故无需设定端口
            DatagramSocket socket = new DatagramSocket();
            //生成待发送数据缓冲区并写入数据
            byte[] buffer = "HelloWorld".getBytes();
            //利用InetAddress获取目标IP地址,这里发送的时本机
            InetAddress address = InetAddress.getByName("localhost");//192.168.131.131
            /* 生成待发送的DatagramPacket,端口值必须与接收端的监听端口 地址一致*/
            DatagramPacket packet = new DatagramPacket(buffer, buffer.length, address,1081);
            //调用send方法发送数据
            socket.send(packet);
            socket.close();
        } catch (Exception e){
            e.printStackTrace();
        }
    }
}

3.实验结果
在这里插入图片描述
这是一次UDP收发信的结果(拆包信息)。如果想要实现前面TCP一样的来回发信只需重复的实现这样的一对代码即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值