我之前上java课程设计的socket通信时,由于对socket相关概念不清晰,导致自己不理解两台电脑如何用socket进行通信,最近前后端分离需要用到socket技术,所以用eclipse来举个较为简单详尽的例子。
socket简要理解
TCP与socket
计算机网络学习中传输层有两个重要协议分别是TCP和UDP,而我们的socket技术是基于TCP的,也因此socket的服务端和客户端必须要本机ip和端口,因为涉及到三次握手。
ip写法
客户端创建socket对象,往往需要提供服务端的ip地址,而由于学习时服务器端和客户端都再一台电脑上,导致对ip地址理解不够深入。
在学习过程中,服务器端代码往往写成诸如:Socket socket = new Socket("localhost",8888);而计算机网络中有一些特殊的ip地址,127.0.0.1就是本机的回环地址,用于测试使用。而localhost与127.0.0.1的关系就相当于DNS,是一种一一对应的关系,因此,
Socket socket = new Socket("localhost",8888);
可以等效于:
Socket socket = new Socket("127.0.0.1",8888);
有人可能会有疑问,回环地址和本机地址有区别吗?什么环境下有区别?
答:回环地址用于测试,即不考虑外部环境情况,也就是说,不会因为断网等问题出现连接问题,也不会被防火墙等拦截。
因此,想要使用联网后的ip地址与其他电脑通信,第一步就需要跨越防火墙的拦截。(当然,是在局域网内,如果不在同一个网络下会出现问题,这里不详细讲)
实现与服务器端通信
查看服务器端ip地址:输入ipconfig命令
虚拟机的使用会提供虚拟ip地址,因此上图的ip地址并非我们要找的。
找到如下图的ip信息,下图IPv4信息就是我们要的地址。
防火墙允许eclipse进行通信
打开控制面板,按上方的路径进入该页面
点击左侧:允许应用或功能通过Windows Defender 防火墙
进入后:点击更改设置,找到如下页面
将java(TM)platform se binary的专用和公用都打钩,由于我安装了多个java,所以全打钩即可。
最后点击下方确定即可。
至此所有准备完成。
代码
类名称:Client指的是客户端,Server指的是服务端
代码中的localhost需要改成服务器端代码
package com.javaob.c30;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
public class Client2 {
/**
* 1 创建客户端,指定服务器+端口,此时键在连接
* Socket(String host,int port)
* 2 接受数据 is + 发送数据 os
* */
public static void main(String[] args) throws UnknownHostException, IOException {
//创建客户端,需指定服务器+端口,此时键在连接
//这里要改成服务器端的代码!!!!!
Socket socket = new Socket("localhost",8888);
//接受数据getInputStream()流
InputStream is = socket.getInputStream();
OutputStream os = socket.getOutputStream();
byte[] b = new byte[20];
int len;
//is对象是输入流对象,本段代码的is是从socket获得并创建的
//is就有了线程的概念,is.read()方法是线程阻塞的方法
//也就是说is.read()方法,只要不被告知数据已发送完毕,is.read()方法就会一直等待
//解决:对方(服务器端)要通过socket.shutdownOutput()方法给客户端
while((len=is.read(b))!=-1) {
String str = new String(b,0,len);
System.out.println("客户端,来自服务器的数据---" + str);
}
String message = "唯有暴富";
System.out.println("客户端的消息发送的消息---" + message);
os.write(message.getBytes());
os.flush();
os.close();
is.close();
}
}
package com.javaob.c30;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Server2 {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
ServerSocket server3 = new ServerSocket(8888);
Socket socket = server3.accept();
System.out.println("服务器的socket对象愿意与一个客户端连接");
OutputStream os = socket.getOutputStream();
String message = "何以解忧";
System.out.println("向客户端发送消息----"+message);
os.write(message.getBytes());
os.flush();
//如果数据发送完毕,则需要给对方一个数据发送完毕的明确信号
socket.shutdownOutput();
InputStream is = socket.getInputStream();
byte[] b = new byte[20];
int len;
while((len=is.read(b))!=-1) {
String str = new String(b,0,len);
System.out.println("服务端,来自客户端的数据---" + str);
}
os.close();
is.close();
}
}