[Java网络编程]Java--socket单向通信的基础模式

前提紧要

使用流需要抛出异常,IEDA按Alt + Enter自动补全抛出异常,也就是在方法处添加throws IOException

在这里插入图片描述

socket通信的基础模式

  1. 指定服务端与端口
  2. 创建socket并连接服务端
  3. 创建流,通过流写入/获取数据
  4. 关闭流,关闭socket

客户端

1.定义服务器信息(ip&port)

ip用字符串存,端口用整数存,端口最好写大点(5000以上)

String server_ip = "127.0.0.1";
int server_port = 8557;

2.创建socket并连接服务端

创建socket时可以使用构造函数指定服务端ip和端口,如果不指定ip则默认为本地回环

Socket socket = new Socket(server_ip,server_port);

3.连接成功后创建输出流

因为程序是客户端,需要输出数据到流中,所以用的是输出流。

这里可大有文章,首先是要看发送的是什么类型的数据,如果是字符,就用字符流,其他文件就用字节流。

输出流也可以使用Buffered类装饰,提高读写效率。

os.write()将数据写入到流中,数据的类型是byte

String message = "to Server: Im client!";//发送的数据
OutputStream os = socket.getOutputStream();//输出流
os.write(message.getBytes(StandardCharsets.UTF_8));//将数据转换成byte类型

os.write(message.getBytes(StandardCharsets.UTF_8))拆开分析

  1. .getBytes():将数据按指定字符集转换成byte--既然你写入要的是byte那我就转换一下咯
  2. StandardCharsets.UTF_8:就是表示UTF-8字符集的意思

注意客户端和服务端的字符集要统一,如果写入用的utf-8那读取也应该用utf-8

4.各种关闭

os.close();//关闭输出流
socket.close();//关闭客户端socket

服务端

1.创建监听端口

就是指定要监听哪个端口

int port = 8557;

2.创建ServerSocket并监听

ServerSocket:因为服务端socket需要的功能和客户端有些出入,比如阻塞监听等,ServerSocket就是用来提供这些服务端所需功能的类,ServerSocket都是配合Socket使用的

ServerSocket server = new ServerSocket(port);//服务端监听的端口

3.监听连接

accept()阻塞端口,直到有客户端向该端口发起连接,返回一个socket。由此可见,服务端一开始并没有socket,而是使用serversocket去监听连接,直到收到客户端的连接后才创建socket,进行信息传输。

Socket socket = server.accept();//阻塞并等待连接请求,accept()返回一个socket

4.创建输入流,接受并处理数据

看码说话

由于数据在流中,所以需要创建一个输入流,获取流中的数据。就像前面客户端写入流时需要进行数据处理一样,服务端从流中读取数据一样需要进行数据处理(而且更麻烦…)需要用到StringBuilder类

StringBuilder用于将其他类型数据拼接成字符串类型。

new String(byte[],offset,length,charset)将byte数组拼接成字符串

append()将其他类型数据拼接成String,能大部分基本的数据类型,如String、char[],包括StringBuilder

  • offset:从哪个位置开始拼接
  • length:每次拼接几个byte
  • charset:按照哪个字符集编码

read()从bytes[]中读取1byte数据,当数组中没有数据时,就会返回-1

代码:

InputStream is = socket.getInputStream();//创建输入流,从客户端socket的流中获取输入
        int len;
        byte[] bytes = new byte[1024];//存储读取到的字节
        StringBuilder sb = new StringBuilder();
        while ((len = is.read(bytes)) != -1){
            //拼接byte组成字符串
            sb.append(new String(bytes,0,len, StandardCharsets.UTF_8));//bytes--字节数组;offset--组装开始位置;length--每次拼接的byte个数,最后一个是字符集
        }

这个循环条件的意思是向byte[]中读取数据,而当里面没有数据可以读的时候会返回-1,结束循环(貌似流中的数据读一个就少一个???)

5.各种关闭

is.close();
server.close();
socket.close();

完整代码

服务端

import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;

public class Server {
    //socket服务端
    public static void main(String[] args) throws IOException {
        int port = 8557;
        /*
        * ServerSocket何许人也?ServerSocket是专门为服务端所用的Socket类,有很多服务端用的函数,比如.accept()用于阻塞监听等
        * */
        ServerSocket server = new ServerSocket(port);//服务端监听的端口

        //服务端开始监听,等待客户端发起连接请求
        System.out.println("waiting for connection....");
        //实际上通讯还是靠Socket类来完成,ServerSocket提供了很多方便服务端去做的事而已,现在这个阻塞就是
        Socket socket = server.accept();//阻塞并等待连接请求,accept()返回一个socket

        //建立连接后
        System.out.println("连接成功!来自...");
        InputStream is = socket.getInputStream();//创建输入流,从客户端socket的流中获取输入
        //is.read()--从流(is)中获取数据下一byte数据,当byte读取完毕后,返回-1。如果有byte数组作为参数,则将读取到的数据存储到byte中
        int len;
        byte[] bytes = new byte[1024];//存储读取到的字节
        StringBuilder sb = new StringBuilder();
        //len = is .read(bytes)这个条件写的可真牛逼啊,如果读取到byte了,会存入到bytes中,如果读完了,就把-1赋给len,循环结束
        while ((len = is.read(bytes)) != -1){
            //拼接byte组成字符串
            sb.append(new String(bytes,0,len, StandardCharsets.UTF_8));//bytes--字节数组;offset--组装开始位置;length--每次拼接的byte个数,最后一个是字符集
        }
        System.out.println("来自客户端的消息:"+sb);
        is.close();
        server.close();
        socket.close();
    }
}

客户端

import java.io.*;
import java.net.Socket;
import java.nio.charset.StandardCharsets;

public class Main {
    public static void main(String[] args) throws IOException {
        //发起连接,Socket类有不同参数的构造函数,只指定端口时,默认服务器ip为本地回环
        String server_ip = "127.0.0.1";
        int server_port = 8557;
        System.out.println("正在向服务端发起连接...");
        Socket socket = new Socket(server_ip,server_port);

        //连接成功后
        System.out.println("连接成功,服务端...");
        //创建输出流
        OutputStream os = socket.getOutputStream();//程序对外的输出流,通过socket获取就是对server的输出流,可以使用Bufferd提高效率
        String message = "to Server: Im client!";//发往server的数据,这里可大有文章,发什么东西就用什么流,字符用字符流,图片啥的用字节流
        //将消息写入输出流里(啥叫水流一般传输数据)
        //getBytes(String charsetName)--将变量按指定字符集编码为bytes序列,并将结果返回到一个新的byte数组中在,可以看到os.write这个方法操作的正是byte数组
        os.write(message.getBytes(StandardCharsets.UTF_8));
        os.close();//关闭输出流
        socket.close();//关闭客户端socket
        //这时,数据就顺着socket的输出流流到了服务端
	}
}

Summary

怪只怪自己Java没学多深,又要花时间去学一下IO流,前后花了整整两天才弄明白这个java的socket通信的基础模式。感觉就是数据的处理上有些麻烦、晦涩。其实大一的时候就用python写过socket,不过那时候是照猫画虎,不求甚解。在其他的语言中socket的用法应该都是大同小异的吧…对了,这些代码并不是我自己原创的,也是跟着网上的帖子写的只是在边写边学的过程中加了一些自己的见解,希望我发博客的时候记得注明出处。
出处:Java Socket编程基础,原文写的很好,还有优化模式

刚开始写的时候不知道从哪里开始,因为这个东西嘛,是两个端的交互,有点拎不清,后面有时间要去学一下优化。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值