专栏首页Java研发军团初学者第70节网络编程-Socket(一)

初学者第70节网络编程-Socket(一)

引言

网络编程是指编写运行在多个设备(计算机)的程序,这些设备都通过网络连接起来。

java.net 包中 J2SE 的 API 包含有类和接口,它们提供低层次的通信细节。你可以直接使用这些类和接口,来专注于解决问题,而不用关注通信细节。

java.net 包中提供了两种常见的网络协议的支持:

TCP:TCP 是传输控制协议的缩写,它保障了两个应用程序之间的可靠通信。通常用于互联网协议,被称 TCP / IP。

UDP:UDP 是用户数据报协议的缩写,一个无连接的协议。提供了应用程序之间要发送的数据的数据包。

以上2中都是客户端/服务器通信模式

UDP上一节已经讲解了比较简单。现在来讲解TCP。

TCP协议及端口

IP协议在发送数据包时,途中会遇到各种事情。例如,可能路由器突然崩溃,使包丢失。又如一个包可能沿低速链路移动,而另一个包可能沿高速链路移动而超过前面的包,最后使得包的顺序搞乱。

TCP协议使两台主机上的进程顺利通信,不必担心包丢失或包顺序搞乱。TCP跟踪包顺序,并且在包顺序搞乱时按正确顺序重组包。如果包丢失,则TCP会请求源主机重发包。

现在来看一张图

上图两台主机上都会运行许多进程。当主机A上的进程A1向主机B上的进程B1发送数据时,IP协议根据主机B的IP地址,把进程A1发送的数据送达主机B。接下来TCP需要决定把数据发送到主机B中的哪个进程。TCP采用端口来区分进程。端口不是物理设备,而是用于标识进程的逻辑地址,更确切地说,是用于标识TCP连接的端点的逻辑地址。当两个进程进行一次通信,就意味着建立了一个TCP连接,TCP连接的两个端点用端口来标识。

在图中,进程A1与进程B1之间建立了一个TCP连接,进程BI的端口为80,因此进程B1的地址为主机B:80。进程A1的端口为1000,因此进程A1的地址为主机A:1000。每个进程有了唯一的地址,TCP就能保证把数据顺利送达特定的进程。

客户端/服务端通讯模式

TCP/UDP协议推动了客户服务器通信模式的广泛运用。在通信的两个进程中,一个进程为客户进程,另一个进程为服务器进程。客户进程向服务器进程发出要求某种服务的请求,服务器进程响应该请求。

如上图所示:通常一个服务器进程会同时为多个客户进程服务,图中服务器进程B同时为客户进程A1、A2和B2提供服务。

好了说了这么多了都是理论,写个小例子吧!!!

客户端/服务端代码演示

写代码之前先介绍下服务端和客户端的编写步骤

服务端步骤:

1. 创建ServerSocket对象server+服务端的端口

2. 监听所有客户端,等待客户端链接请求socket对象

3.使用socket对象的getinputStream方法获取客户端发送过来的数据的流对象

或者使用socket对象的getOutputStream方法向客户端发送数据的流对象

4.获取数据或者发送数据

5.关闭server资源

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class TcpServer {
    public static void main(String[] args){
        final int port = 30000;
        /**
         1. 创建ServerSocket对象server
         2. 监听所有客户端,等待客户端链接请求socket对象
         3.使用socket对象的getOutputStream方法获取客户端发送过来的数据的流对象
         或者使用socket对象的getinputStream方法向客户端发送数据的流对象
         4.获取数据或者发送数据
         5.关闭server资源
         */
        //创建ServerSocket对象server
        ServerSocket server = null;
        try {
            server = new ServerSocket(port);
            while (true) {
                //监听所有客户端,等待客户端链接请求socket对象
                Socket socket = server.accept();
                System.out.println("客户端ip:"+socket.getInetAddress().getHostName() + "端口为:"+  socket.getPort()+"链接成功。。。");
                //使用socket对象的getOutputStream方法获取客户端发送过来的数据
                ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());
                //读取数据
                Object object = objectInputStream.readObject();
                System.out.println("server获取数据为:" + object);
                //使用socket对象的getinputStream方法向客户端发送数据
                ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());

客户端步骤:

1. 创建socket对象,指定服务器ip和端口

2. 使用socket对象的getinputStream方法获取客户端发送过来的数据的流对象

或者使用socket对象的getOutputStream方法向客户端发送数据的流对象

3.获取数据

4.关闭socket资源

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;

public class TcpClient {

    public static void main(String[] args) {
        /**
         1. 创建socket对象,指定服务器ip和端口
         2. 使用socket对象的getinputStream方法获取客户端发送过来的数据的流对象
         或者使用socket对象的getOutputStream方法向客户端发送数据的流对象
         3.获取数据
         4.关闭socket资源
         */
        final int port = 30000;
        Socket client = null;
        try {
            //创建socket对象,指定服务器ip和端口
            client = new Socket("127.0.0.1",port);
            //使用socket对象的getOutputStream方法向客户端发送数据的流对象
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(client.getOutputStream());
            objectOutputStream.writeObject("我是客户端");

            //使用socket对象的getinputStream方法获取客户端发送过来的数据的流对象
            ObjectInputStream objectInputStream = new ObjectInputStream(client.getInputStream());
            //获取数据
            Object object = objectInputStream.readObject();
            System.out.println("客户端显示服务端传过来的数据:"+object);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            if (client != null) {
                try {
                    //关闭socket资源
                    client.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

运行结果

服务端结果
客户端ip:127.0.0.1端口为:52499链接成功。。。
server获取数据为:我是客户端
客户端结果:
客户端显示服务端传过来的数据:我是服务器

注意:服务端在接收数据时客户端一定不能关闭,如果关闭会报java.net.SocketException: Software caused connection abort: socket write error异常

本文分享自微信公众号 - Java研发军团(ityuancheng),作者:猿程之家

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2018-05-08

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 如何设计一个百万级的NB消息推送系统!!!

    先简单说下本次的主题,由于我最近做的是物联网相关的开发工作,其中就不免会遇到和设备的交互。

    用户5224393
  • 深入剖析mybatis原理(二)

    我们接下来要看看 SqlSession 的创建过程和运行过程,首先调用了 sqlSessionFactory.openSession() 方法。该方法默认实现类...

    用户5224393
  • WebSocket实现Web端即时通信

    HTTP协议是半双工协议,也就是说在同一时间点只能处理一个方向的数据传输,同时HTTP消息也是过于庞大,里面包含大量消息头数据,真正在消息处理中很多数据不是必须...

    用户5224393
  • 3次握手+4次挥手+11种状态集

    TCP也叫传输控制协议(Transmission Control Protocol)是一种面向连接的、可靠的、基于字节流的传输层通信协议,由IETF的RFC 7...

    有暗香盈袖
  • BIO、NIO

    我们平常使用的IO是BIO(Blocking-IO),即阻塞IO、而NIO(No-blocking-IO)则是非阻塞IO,二者有什么区别呢?

    Howl
  • 【分布式锁】07-Zookeeper实现分布式锁:Semaphore、读写锁实现原理

    前面已经讲解了Zookeeper可重入锁的实现原理,自己对分布式锁也有了更深的认知。

    一枝花算不算浪漫
  • 模型调参:压力也没那么大,试了一圈还是得靠贝叶斯

    大数据文摘
  • JavaScript array merge 数组合并

    Dilemma of speed/time and space/memory. a javascript speed & space case.

    readme
  • 全局自动优化:C+机器学习库dlib引入自动调参算法

    选自dlib Blog 机器之心编译 参与:路雪、李泽南、蒋思源 dlib 是一个开源的 C++ 机器学习算法工具包,被广泛用于工业界和学术界,覆盖机器人、嵌入...

    企鹅号小编
  • SrpingCloud ---github上面如何使用webHook实现配置文件修改 ,客户端自动刷新

    增加了spring-boot-starter-actuator包,spring-boot-starter-actuator是一套监控的功能,可以监控程序在运行时...

    爱明依

扫码关注云+社区

领取腾讯云代金券