java单工通讯_java中用socket实现简单的单工通信-Go语言中文社区

我们都知道本地计算机在线程通信时可以根据每个进程的PID来识别不同的程序

但如果一台计算机和另外一台计算机进行通信时光靠进程的PID是不行的,因为进程在生成时的PID也是随机的。

网络中的TCP/IP协议加上端口可以唯一确定一台计算机的某个进程,IP确定了是哪台计算机,端口号又确定了了是哪个进程。

本机进行数据交流时可以通过OutputStream、InputStream这样的IO数据流来进行信息传递

需要通过网络传递数据时就可以用Socket这个类了。

1cdfe018d259b759533a085f3be66780.png

数据在网络里也是一层套一层地包装好然后发给对方的,如果把数据比作货车上的货品,Socket差不多就是货车负责记录自己从哪里来(自己的本地IP地址),要到哪个工厂(对方的IP地址),货品都对应工厂的哪个仓库(端口)。

d0d39f235bdffa6c4faffc83bc978748.png

根据上图可知,首先得有一个服务器来等待客户端发数据

实例化一个ServerSocket对象,并传入一个端口参数,这里建议用2000到65535的参数,因为之前的端口可能已经被系统某个进程使用了。这里服务器端口参数为8888,所以想和他连接的客户端程序端口也要设置成8888。new ServerSocket(8888);

既然是服务器,当然也要知道自己的IP,但是new ServerSocket(8888)并没有设置

虽然用的是一个参数的构造方法但也会调用三个参数的构造方法,同时将端口号传了过去

4624c7537887397ccaf87970f3fcdd23.png

backlog是连接队列,系统以及提供了默认值,想修改的话也可以用两个参数的构造方法

在三个参数的构造方法里又自动实例化了一个InetSocketAddress对象

50bb7703444353d3a3d770f67d80e894.png

InetSocketAddress已经自动调用其他方法获取到了本地IP地址。

这就是唯一确定的服务器进程实例化的大致流程。

f30bf0bcef6de2a9602ce587547a15bb.png

3bf721fc39b69a037c21fe939061f2c0.png

数据流都是一层套一层,而ServerSocket是最外层,所以accept()方法可以获取内部的某层数据流,应该可以这样理解。

接下来就是数据流之间的互相传递数据了,需要注意的是:

在用Socket通信时,由于是网络通信所以要用网络数据流,比如常见的DataInputStream,否则数据格式不对。

如果用键盘写入数据推荐用BuffereReader写,用Scanner直接写给网络数据流的readUTF()会出错。因为Scanner从键盘获取的值并不是IO数据流的格式,就没法在它的基础上继续包装。而BuffereReader符合数据流的格式从而可以在它的基础上在包装成网络数据流格式。

此例子仅是单工通信,也就是客户端写一个服务器读取一个,然后服务器再写一个客户端再读一个。

服务器代码如下:public class ServeTest {

public static void main(String[] args) throws IOException {

ServerSocket serverSocket = new ServerSocket(8888);

Socket accept = serverSocket.accept();

InputStream inputStream = accept.getInputStream();

OutputStream outputStream = accept.getOutputStream();

DataInputStream dis= new DataInputStream(inputStream);

DataOutputStream dos=new DataOutputStream(outputStream);

BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

String account=dis.readUTF();

String password=dis.readUTF();

System.out.println("账号:"+account+",密码:"+password);

while (!account.equals("哔哔小子")||!password.equals("123")) {

System.out.println("输入错误");

dos.writeUTF("输入错误");

account=dis.readUTF();

password=dis.readUTF();

}

dos.writeUTF("输入正确");

System.out.println("验证通过");

while(true){

String info=dis.readUTF();

System.out.print("客户端说:"+info+"n");

if (info.equals("bye"))

break;

System.out.print("我:");

dos.writeUTF(br.readLine());

System.out.println();

}

br.close();

dos.close();

dis.close();

}

}

客户端的Socket初始化和ServerSocket基本上差不多,需要注意的是:

既然是在本机上的模拟网络通信,所以能用的IP地址就是本机的IP地址,实例化Socket时传入的IP地址可以是本机IP地址也可以是"127.0.0.1",这个特殊地址是回路地址,就是用来测试本地连接用的。

如果服务器或者客户端还在读取数据,对方对应的Scoket先结束了,会报错。

客户端只要不结束,服务器的网络数据流在read()时就会一直进入阻塞状态直到对方发来数据

客户端代码如下:public class ClientTest {

public static void main(String[] args) throws Exception, IOException {

Socket socket = new Socket("127.0.0.1",8888);

Scanner scanner = new Scanner(System.in);

OutputStream outputStream = socket.getOutputStream();

InputStream inputStream = socket.getInputStream();

DataOutputStream dos = new DataOutputStream(outputStream);

DataInputStream dis = new DataInputStream(inputStream);

BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

System.out.println("输入账号:");

//String account=scanner.nextLine();必须要有参数接收,否则直接data写会出错

dos.writeUTF(br.readLine());

System.out.println("输入密码");

//String password=scanner.nextLine();也是问题

dos.writeUTF(br.readLine());

String info=dis.readUTF();

while (info.equals("输入错误")){

System.out.println("输入有误,请重新输入!");

System.out.println("输入账号:");

dos.writeUTF(br.readLine());

System.out.println("输入密码");

dos.writeUTF(br.readLine());

info=dis.readUTF();

}

System.out.println("已连接到主机");

System.out.println("进入聊天模式");

while(true){

System.out.print("我:");

String message=br.readLine();

System.out.println();

dos.writeUTF(message);

if (message.equals("bye"))

break;

message=dis.readUTF();

System.out.print("服务器说:"+message+"n");

}

br.close();

dos.close();

dis.close();

}

}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值