Java Socket网络编程

一.Socket概述

​ Java网络编程主要涉及的内容是Socket编程。

​ Socket(套接字),是网络上两个程序之间实现数据交换的一端,它既可以发送请求,也可以接受请求,一个Socket由一个IP地址和一个端口号唯一确定,利用Socket能比较方便的实现两端(服务端和客户端)的网络通信。

​ 在Java中,有专门的Socket类来处理用户请求和响应,学习使用Socket类方法,就可以实现两台机器之间通信。

Socket通信是有两种方式的:TCP和UDP。

​ TCP通信:客户端提供了java.net.Socket类,服务器端提供了java.net.ServerSocket类。

​ UDP通信:UDP通信不建立逻辑连接,使用DatagramPacket类打包数据包,使用DatagramSocket类发送数据包。

Socket通信模型如下图:

在这里插入图片描述

二. TCP通信客户端Socket

​ Java中专门用来实现Socket客户端的类就叫Socket,这个类实现了客户端套接字,用于向服务器发出连接请求等。

  • 构造方法:

    Socket(String host, int port):创建一个流套接字并将其连接到指定IP地址的指定端口号。

    如果host为null,则相当于指定地址为回送地址。

    回送地址(来自百度百科):

    ​ 127.x.x.x是本机的会送地址,即主机IP堆栈内部的IP地址,主要用于网络软件测试以及本地机进程间通信,无论什么程序,一旦使用回送地址发送数据,协议软件立即返回之,不进行任何网络传输。

  • 主要方法:

    • InputStream getInputStream():返回此套接字的输入流。

      关闭生成的InputStream也将关闭相关的Socket。

    • OutputStream getOutputStream():返回此套接字的输出流。

      关闭生成的OutputStream也将关闭相关的Socket。

    • void close():关闭此套接字

三. TCP通信服务器端ServerSocket

​ Java中专门用来建立Socket服务器的类叫ServerSocket,这个类实现了服务器套接字,该对象等待通过网络的请求。

  • 构造方法:

    ServerSocket(int port):创建绑定到特定端口的服务器套接字。

  • 主要方法:

    • Socket accept():监听并接受连接,返回一个新的Socket对象,用于和客户端通信,该方法会一直阻塞直到建立连接。

    • void close():关闭此套接字。

四.基于TCP的Socket通信

  1. 步骤分析:

    • 服务端先启动,创建ServerSocket对象,等待连接。
    • 客户端启动,创建Socket对象,请求连接。
    • 服务器端接收请求,调用accept方法,并返回一个Socket对象。
    • 客户端的Socket对象获取OutputStream,向服务器端发送数据。
    • 服务器端Socket对象获取InputStream,读取客户端的数据。
    • 服务器端Socket对象获取OutputStream,向客户端发送数据。
    • 客户端的Socket对象获取InputStream,读取服务器的数据。
    • 客户端释放资源,断开连接。
  2. 主要代码

    • 服务器端

      import java.io.*;
      import java.net.ServerSocket;
      import java.net.Socket;
      
      
      public class TCPServer {
          public static void main(String[] args) throws IOException {
              System.out.println("Server start...");
              ServerSocket server = new ServerSocket(1234);
              
              while (true) {
                  Socket client = server.accept();
      
                  // 字节流转为字符流
                  InputStreamReader isr = new InputStreamReader(client.getInputStream());
                  // 字符流转换为缓冲流
                  BufferedReader br = new BufferedReader(isr);
      
                  // 读取
                  String line = null;
                  while ((line = br.readLine()) != null) {
                      System.out.println("接收到客户端信息:" + line);
                  }
      
                  // 发送信息到客户端 字节流转字符流
                  OutputStreamWriter out = new OutputStreamWriter(client.getOutputStream());
                  // 字符流转换为缓冲流
                  BufferedWriter bw = new BufferedWriter(out);
                  
                  String str = "你好,服务器收到了";
                  bw.write(str);
                  bw.flush();
      
                  // 关闭资源
                  client.close();
              }
          }
      }
      
    • 客户端

      import java.io.*;
      import java.net.Socket;
      
      public class TCPClient {
          public static void main(String[] args) throws IOException {
              System.out.println("Client start...");
              Socket client = new Socket("localhost", 1234);
      
              OutputStreamWriter osw = new OutputStreamWriter(client.getOutputStream());
              BufferedWriter bw = new BufferedWriter(osw);
      
              String str = "你好,我是客户端";
              bw.write(str);
              bw.flush();
      
              // 发送一个终结符,告诉服务器,已经发送完毕
              client.shutdownOutput();
      
              InputStreamReader isr = new InputStreamReader(client.getInputStream());
              BufferedReader br = new BufferedReader(isr);
      
              String line = null;
      
              while((line = br.readLine()) != null) {
                  System.out.println("接收到服务器消息:" + line);
              }
      
              // 释放资源
              client.close();
          }
      }
      

      注意:

      ​ 在交互时,服务器accept是阻塞的,read也是阻塞的,所以在发送完数据后,需要调用shutdownOutput来告知发送结束,否则会一直阻塞。

五.UDP相关类DatagramPacket类和DatagramSocket类

  1. 数据包类DatagramPacket
    • 作用:用来封装发送端或接收端要发送或接收的数据。
    • 构造方法
      • DatagramPacket(byte[] buf, int length):构造DatagramPacket,用来接收长度为length的数据包。
      • DatagramPacket(byte[] buf, int length, InetAddress address, int port):构造数据报包,用来将长度为length的包发送到指定主机上的指定端口号。
    • 常用方法
      • public int getLength():获得发送端实际发送的字节数或接收端世界接收的字节数
      • public int getPort():获得发送端或接收端端口号
  2. 发送数据包类DatagramSocket
    • 作用:用来发送和接收数据包对象
    • 构造方法
      • DatagramSocket():构造数据报套接字并将其绑定到本地主机上任何可用的端口。
      • DatagramSocket(int port):创建数据包套接字并将其绑定到本地主机上指定端口。
    • 常用方法
      • public void send(DatagramPacket p):从此套接字发送数据报包
      • public void receive(DatagramPacket p):从此套接字接收数据报包
      • public void close():关闭此数据报套接字
  3. InetAddress类(无构造方法)
    • 作用:代表一个IP地址
    • 静态方法
      • public static InetAddress getLocalHost():返回本地主机
      • public static InetAddress getByName():在给定主机名的情况下确定主机的 IP 地址。
    • 普通方法
      • public String getHostName(): 获取此 IP 地址的主机名。
      • public String getHostAddress():返回 IP 地址字符串(以文本表现形式)

六.基于UDP的Socket通信

  1. 步骤分析

    • 服务器端先启动,创建DatagramSocket对象,监听端口,用于接收
    • 服务器端创建DatagramPacket对象,打包用于接收的数据包
    • 服务器阻塞等待接收
    • 客户端启动,创建DatagramSocket对象,监听端口,用于接收
    • 客户端创建DatagramPacket对象,打包用于发送的数据包
    • 客户端发送数据,服务端接收
    • 服务端接收数据后,创建DatagramPacket对象,打包用于发送的数据包,发送数据
    • 客户端创建DatagramPacket对象,打包用于接收的数据包,阻塞等待接收
    • 客户端接收服务端数据,断开连接,释放资源
  2. 主要代码

    • 服务器

      import java.io.IOException;
      import java.net.*;
      
      public class UDPServer {
          public static void main(String[] args) throws IOException {
              System.out.println("Server Start...");
      
              // 保存接收的数据
              byte[] rData = new byte[1024];
      
              // 接收时监听端口8888
              DatagramSocket ds = new DatagramSocket(8888);
              DatagramPacket rdp = new DatagramPacket(rData, rData.length);
      
              while (true) {
                  ds.receive(rdp);
                  System.out.println("Receive:" + new String(rData));
      
                  // 发送数据
                  byte[] sData = "你好,我是服务器".getBytes();
                  DatagramPacket sdp = new DatagramPacket(sData, sData.length, rdp.getAddress(), rdp.getPort());
          
                  ds.send(sdp);
              }
          }
      }
      
    • 客户端

      import java.io.IOException;
      import java.net.*;
      
      public class UDPClient {
          public static void main(String[] args) throws IOException {
              System.out.println("Client login...");
              // 构建数据包
              byte[] sendData = "Hello,I am Client".getBytes();
              InetAddress sendAddress = InetAddress.getLocalHost();
              DatagramPacket dp = new DatagramPacket(sendData, sendData.length, sendAddress, 8888);
              DatagramSocket ds = new DatagramSocket(1234);
              ds.send(dp);
      
              // 创建数据包,接收数据
              byte[] receiveData = new byte[1024];
              DatagramPacket rdp = new DatagramPacket(receiveData, receiveData.length);
              ds.receive(rdp);
      
              System.out.println("Receive:" + new String(receiveData));
      
              ds.close();
          }
      }
      

    注意:

    UDP通信双方,对应端口号一致才可以,比如发送方使用1234端口,接收方需要监听1234端口才可以。

  • 2
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
import java.io.*; import java.net.*; import java.util.*; import java.lang.*; public class Server extends ServerSocket { private static ArrayList User_List = new ArrayList(); private static ArrayList Threader = new ArrayList(); private static LinkedList Message_Array = new LinkedList(); private static int Thread_Counter = 0; private static boolean isClear = true; protected static final int SERVER_PORT = 10000; protected FileOutputStream LOG_FILE = new FileOutputStream( "d:/connect.log", true); public Server() throws FileNotFoundException, IOException { super(SERVER_PORT); // append connection log // Calendar now = Calendar.getInstance(); // String str = "[" + now.getTime().toString() + // "] Accepted a connection"; // byte[] tmp = str.getBytes(); // LOG_FILE.write(tmp); try { Socket socket = accept(); while (true) { new ServerReaderThread(socket); new ServerWriterThread(socket); } } finally { close(); } } public static void main(String[] args) throws IOException { new Server(); } // --- CreateServerThread class ServerReaderThread extends Thread { private Socket client; private BufferedReader in; private PrintWriter out; private String Username; public ServerReaderThread(Socket s) throws IOException { client = s; in = new BufferedReader(new InputStreamReader(client .getInputStream())); out = new PrintWriter(client.getOutputStream(), true); start(); } public void run() { try { int flag = 0; Thread_Counter++; String line = in.readLine(); while (!line.equals("bye")) { out.println(line); line = in.readLine(); } out.println("--- See you, bye! ---"); // System.out.println("--- See you, bye! ---"); client.close(); } catch (IOException e) { } finally { try { client.close(); } catch (IOException e) { } Thread_Counter--; } } } // --- CreateServerThread class ServerWriterThread extends Thread { priva

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值