java go tcp通信

场景

在实际开发当中,语言经常会根据业务进行调整,比如网关和探针之间。之间可能都是用java实现,后面由于调整,探针改成go来写,网关不变。这个时候,通信的接口就不要定义开源的私有协议,否则两头都要改。采用最原始的socket通信,就没有这种问题。代码就是demo,仅供参考。

socket服务端 java实现

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

public class SocketDemoServer {
    public static void main(String[] args) {
        ServerSocket serverSocket = null;
        Socket socket = null;
        BufferedReader in = null;
        int port = 9988;
        try {
            serverSocket = new ServerSocket(port);    //创建服务器套接字
            System.out.println("服务器开启,等待连接。。。");
            socket = serverSocket.accept();// 获得链接
            InputStream is = null;
            byte[] bytes = new byte[4096];
            is = socket.getInputStream();
            StringBuilder sb = new StringBuilder();
            while (true) {
                is.read(bytes);
                String msg = new String(bytes);
                System.out.println("客户端发送的内容为:" + msg);
                if (msg == null || msg.contains("end")) {
                    break;
                }
            }
            OutputStream os = socket.getOutputStream();
            BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(os));
            sb.append("这是服务端的一条消息啊");
            writer.write(sb.toString());
            writer.newLine();
            writer.write("end");
            writer.newLine();
            writer.flush();
            socket.close();


        } catch (Exception e) {
            // TODO 自动生成的 catch 块
            e.printStackTrace();
        }
    }
}

socket客户端 go实现

import (
	"bufio"
	"fmt"
	"net"
	"os"
	"strings"
)

func main() {
	conn, err := net.Dial("tcp", "127.0.0.1:9988")
	if err != nil {
		fmt.Println("客户端建立连接失败")
		return
	}
	cConnHandler(conn)
}

func cConnHandler(c net.Conn) {
	//返回一个拥有 默认size 的reader,接收客户端输入
	reader := bufio.NewReader(os.Stdin)
	//缓存 conn 中的数据
	buf := make([]byte, 1024)
	fmt.Println("请输入客户端请求数据...")
	for {
		//客户端输入
		input, _ := reader.ReadString('\n')
		//去除输入两端空格
		input = strings.TrimSpace(input)
		//客户端请求数据写入 conn,并传输
		c.Write([]byte(input))
		//服务器端返回的数据写入空buf
		cnt, err := c.Read(buf)

		if err != nil {
			fmt.Printf("客户端读取数据失败 %s\n", err)
			continue
		}
		fmt.Print("服务器端回复" + string(buf[0:cnt]))
	}
}

测试截图

客户端发消息

附录

顺便贴一下java版的客户端,go的服务端代码,组成完美demo ,百度抄一抄,改一下 。。。

socket客户端 java实现

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.Scanner;

public class TCPClient {
    public static void main(String[] args) throws Exception {

        try {
            while (true){
                Socket socket = new Socket("localhost",9988);
                BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()) );
                Scanner scanner = new Scanner(System.in);
                String str = scanner.nextLine();
                writer.write(str);
                writer.newLine(); //todo 必须加这一句,否则服务端读取的时候可能会阻断,不能读取
                writer.write("end");
                writer.newLine();
                writer.flush();
                
                BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                while (true){
                    String rs = reader.readLine(); //todo while循环读,最后一个都不到的时候会出现阻塞,而不是读出null,所以只能约定读到end时结束
                    if(rs.equals("end")){
                        break;
                    }
                    System.out.println(rs);
                }
                socket.close();
            }
        }catch (Exception e){
            e.printStackTrace();
        }

    }
}

socket客户端 go实现

import (
	"fmt"
	"log"
	"net"
	"strings"
)

/**
  需求:
      socket编程实现 客户端 与 服务端进行通讯
      通讯测试场景:
          1.client 发送 ping, server 返回 pong
          2.client 发送 hello, server 返回 world
          3.其余client发送内容, server 回显即可

  抽象&解决方案:
      1. socket 编程是对 tcp通讯 过程的封装,unix server端网络编程过程为 Server->Bind->Listen->Accept
         go 中直接使用 Listen + Accept
      2. client 与客户端建立好的请求 可以被新建的 goroutine(go func) 处理 named connHandler
      3. goroutine 的处理过程其实是 输入流/输出流 的应用场景

  积累:
      1.基础语法
      2.基本数据结构 slice 使用
      3.goroutine 使用
      4.switch 使用
      4.socket 编程核心流程
      5.net 网络包使用
*/

func connHandler(c net.Conn) {
	//1.conn是否有效
	if c == nil {
		log.Panic("无效的 socket 连接")
	}

	//2.新建网络数据流存储结构
	buf := make([]byte, 4096)
	//3.循环读取网络数据流
	for {
		//3.1 网络数据流读入 buffer
		cnt, err := c.Read(buf)
		//3.2 数据读尽、读取错误 关闭 socket 连接
		if cnt == 0 || err != nil {
			c.Close()
			break
		}

		//3.3 根据输入流进行逻辑处理
		//buf数据 -> 去两端空格的string
		inStr := strings.TrimSpace(string(buf[0:cnt]))
		//去除 string 内部空格
		cInputs := strings.Split(inStr, " ")
		//获取 客户端输入第一条命令
		fCommand := cInputs[0]

		fmt.Println("客户端传输->" + fCommand)
		switch fCommand {
		case "ping":
			c.Write([]byte("服务器端回复-> pong\n"))
		case "hello":
			c.Write([]byte("服务器端回复-> world\n"))
		default:
			c.Write([]byte("服务器端回复" + fCommand + "\n"))
		}

		//c.Close() //关闭client端的连接,telnet 被强制关闭

		fmt.Printf("来自 %v 的连接关闭\n", c.RemoteAddr())
	}
}

//开启serverSocket
func main() {
	//1.监听端口
	server, err := net.Listen("tcp", "127.0.0.1:9988")

	if err != nil {
		fmt.Println("开启socket服务失败")
	}

	fmt.Println("正在开启 Server ...")

	for {
		//2.接收来自 client 的连接,会阻塞
		conn, err := server.Accept()

		if err != nil {
			fmt.Println("连接出错")
		}

		//并发模式 接收来自客户端的连接请求,一个连接 建立一个 conn,服务器资源有可能耗尽 BIO模式
		go connHandler(conn)
	}

}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值