一直感觉socket这个东西挺神秘的 ,觉得是大牛级别的才能驾轻就熟。今天碰巧看了一下socket的相关资料,通过socket实现客户端和服务端的通信,从实战中去体验socket的用处。
先给大家上一张图
这张图大致就是tcp协议和udp协议的分布范围,其中,socket负责的是传输层之间的通信
socket是基于应用服务与TCP/IP通信之间的一个抽象,他将TCP/IP协议里面复杂的通信逻辑进行分装,对用户来说,只要通过一组简单的API就可以实现网络的连接
简而言之,socket已经封装成相应的方法,我们调用相应的方法即可进行socket的使用。
一,创建服务端和客户端的连接
服务端:
public static void main(String[] args) {
try {
//初始化服务端
ServerSocket serverSocket = new ServerSocket(9999);
//等待客户端链接
Socket socket = serverSocket.accept();
//获取输入流
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//读取一行数据
String str = bufferedReader.readLine();
//输出打印
System.out.println("服务端:"+str);
}catch (IOException e){
//抓取初始化服务端的io异常
e.printStackTrace();
}
}
客户端:
public static void main(String[] args) {
try {
//获取服务端的链接
Socket socket = new Socket("127.0.0.1",9999);
//写入输入流
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
//创建输入文字
String str = "你好";
bufferedWriter.write(str);
//刷新输入流
bufferedWriter.flush();
//关闭socket的输入流----此处与close不同,close后会完全关闭,无法接受服务端反馈的信息
socket.shutdownOutput();
}catch (IOException e){
e.printStackTrace();
}
}
注意:1.socket连接需要先启动服务端,再启动客户端,这样客户端才能通过端口号去找到开启服务的socket服务端
2.在客户端中,需要关闭资源,也就是shutdowmOutPut()方法,这个方法的好处是,如果后期做到服务端响应客户端的消息时,客户端是可以接收到的,如果调用的是close()方法,那就真的是关掉整个资源,再也收不到其他消息了。
将服务端和客户端的代码编写完成后,依次启动服务端和客户端,服务端会立即接收到客户端发的信息,如图:
这代表socket中服务端和客户端完成了一次通信,我们在服务端调用相应的方法进行服务端的创建,客户端也是,运用基本的socketAPI完成了一次通信,也是一次对socket的基本知识的熟悉。
二,思考
1.客户端可以发送多条消息吗?
2.服务端能不能响应客户端的信息呢?
3.客户端和服务端能不能正常发信息进行交流?
答案当然是可以的,只不过需要我们去不断的变通。
三,客户端发送多条消息
服务端:
public static void main(String[] args) {
try {
ServerSocket serverSocket = new ServerSocket(9999);
//等待客户端链接
Socket socket = serverSocket.accept();
//获取输入流
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream(),"utf-8"));
String str;
//循环判断是否为空
while((str=bufferedReader.readLine())!=null){
System.out.println("客户端:"+str);
}
}catch (IOException e){
e.printStackTrace();
}
}
客户端:
public static void main(String[] args) {
try {
//获取服务端的链接
Socket socket = new Socket("127.0.0.1", 9999);
//写入输入流
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
//写入输出流
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in,"utf-8"));
//循环
while(true){
String strinput = bufferedReader.readLine();
bufferedWriter.write(strinput);
bufferedWriter.write("\n");
bufferedWriter.flush();
}
} catch (IOException e) {
e.printStackTrace();
}
}
这边在客户端和服务端都加了一个循环,客户端循环读取输入的值,服务端循环读取输出的值,最后如图:
客户端实现
服务端实现
通过一个循环,就可以解决发送多条通信的问题
四,服务端和客户端进行互通交流
服务端和客户端想要进行互相通信,那就需要两者具备接收和发送信息的功能,并且相应的创建文件的位置是比较重要的,否则会出现服务端永远响应一条信息,错误实例如图:
此图是服务端代码有误,就像foreach循环一样,初始化代码的地方有误,会导致后续的代码取值全部相同,这里就是在第二行全部取空值。
正确服务端代码如下;
public static void main(String[] args) {
try {
ServerSocket serverSocket = new ServerSocket(9999);
//等待客户端链接
Socket socket = serverSocket.accept();
//获取输出流
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), "utf-8"));
//循环判断是否为空
//while((str=bufferedReader.readLine())!=null){
Scanner sc = new Scanner(System.in);
while (true) {
//获取输入流
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream(), "utf-8"));
String str = bufferedReader.readLine();
System.out.println("客户端:" + str);
System.out.println("请反馈客户端");
String strs = sc.nextLine();
bufferedWriter.write(strs);
bufferedWriter.write("\n");
bufferedWriter.newLine();
bufferedWriter.flush();
}
} catch (IOException e) {
e.printStackTrace();
}
}
客户端代码:
public static void main(String[] args) {
try {
//获取服务端的链接
Socket socket = new Socket("127.0.0.1", 9999);
//循环
Scanner scanner = new Scanner(System.in);
while(true){
System.out.println("请输入发送消息内容:");
String str = scanner.nextLine();
//写入输入流
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
bufferedWriter.write(str);
bufferedWriter.write("\n");
bufferedWriter.newLine();
bufferedWriter.flush();
//写入输出流
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String ret = bufferedReader.readLine();
System.out.println("服务器端返回过来的是: " + ret);
/*String ret;
while((ret=bufferedReader.readLine())!=null){
System.out.println("服务器端返回过来的是: " + ret);
}*/
}
} catch (IOException e) {
e.printStackTrace();
}
}
通信客户端:
通信服务端:
这样就实现了服务端和客户端之间的通信。
现在是做一些这方面的积累,等待真正使用的时候不至于手忙脚乱。
让我们一起好好学习天天向上吧!