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

java中用socket实现简单的单工通信


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

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

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

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

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


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


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

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

new ServerSocket(8888);

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

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


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

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


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

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


数据流都是一层套一层,而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();
	}
}

版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/bibiboyx/article/details/80066916
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2020-03-07 07:00:34
  • 阅读 ( 1137 )
  • 分类:

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢