Socket 通信原理

整理和总结了一下大家常遇到的问题:

1.  客户端socket发送消息后,为什么服务端socket没有收到?

2.  使用while 循环实现连续输入,是不是就是多线程模式?

3.  对多线程处理机制不是很明白,希望详细讲解?

4.  希望详细讲解ServerSocketChannel和SocketChannel与ServerSoket和Socket的区别?

5.  希望有详细的例子,可以直接拷贝下来运行?

针对童鞋们提出的问题,我会在本文章中详细一一简答,并且给出详细的例子,下面言归正传。

一:socket通信基本原理。

首先socket 通信是基于TCP/IP 网络层上的一种传送方式,我们通常把TCP和UDP称为传输层。

图片描述(最多50字)

如上图,在七个层级关系中,我们将的socket属于传输层,其中UDP是一种面向无连接的传输层协议。UDP不关心对端是否真正收到了传送过去的数据。如果需要检查对端是否收到分组数据包,或者对端是否连接到网络,则需要在应用程序中实现。UDP常用在分组数据较少或多播、广播通信以及视频通信等多媒体领域。在这里我们不进行详细讨论,这里主要讲解的是基于TCP/IP协议下的socket通信。

socket是基于应用服务与TCP/IP通信之间的一个抽象,他将TCP/IP协议里面复杂的通信逻辑进行分装,对用户来说,只要通过一组简单的API就可以实现网络的连接。借用网络上一组socket通信图给大家进行详细讲解:

图片描述(最多50字)

首先,服务端初始化ServerSocket,然后对指定的端口进行绑定,接着对端口及进行监听,通过调用accept方法阻塞,此时,如果客户端有一个socket连接到服务端,那么服务端通过监听和accept方法可以与客户端进行连接。

二:socket通信基本示例:

在对socket通信基本原理明白后,那我们就写一个最简单的示例,展示童鞋们常遇到的第一个问题:客户端发送消息后,服务端无法收到消息。

服务端:

package socket.socket1.socket;

import java.io.BufferedReader;

import java.io.BufferedWriter;

import java.io.IOException;

import java.io.InputStreamReader;

import java.net.ServerSocket;

import java.net.Socket;

public class ServerSocketTest {

public static void main(String[] args) {

try {

// 初始化服务端socket并且绑定9999端口

  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) {

e.printStackTrace();

}

}

}

客户端:

package socket.socket1.socket;

import java.io.BufferedWriter;

import java.io.IOException;

import java.io.OutputStreamWriter;

import java.net.Socket;

public class ClientSocket {

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="你好,这是我的第一个socket";

  bufferedWriter.write(str);

}catch (IOException e) {

e.printStackTrace();

}

}

}

启动服务端:

发现正常,等待客户端的的连接

图片描述(最多50字)

启动客户端:

发现客户端启动正常后,马上执行完后关闭。同时服务端控制台报错:

图片描述(最多50字)

服务端控制台报错:

图片描述(最多50字)

然后好多童鞋,就拷贝这个java.net.SocketException: Connection reset上王查异常,查询解决方案,搞了半天都不知道怎么回事。解决这个问题我们首先要明白,socket通信是阻塞的,他会在以下几个地方进行阻塞。第一个是accept方法,调用这个方法后,服务端一直阻塞在哪里,直到有客户端连接进来。第二个是read方法,调用read方法也会进行阻塞。通过上面的示例我们可以发现,该问题发生在read方法中。有朋友说是Client没有发送成功,其实不是的,我们可以通debug跟踪一下,发现客户端发送了,并且没有问题。而是发生在服务端中,当服务端调用read方法后,他一直阻塞在哪里,因为客户端没有给他一个标识,告诉是否消息发送完成,所以服务端还在一直等待接受客户端的数据,结果客户端此时已经关闭了,就是在服务端报错:java.net.SocketException: Connection reset

那么理解上面的原理后,我们就能明白,客户端发送完消息后,需要给服务端一个标识,告诉服务端,我已经发送完成了,服务端就可以将接受的消息打印出来。

通常大家会用以下方法进行进行结束:

socket.close() 或者调用socket.shutdownOut

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值