Socket和ServerSocket

对于即时类应用或者即时类的游戏,HTTP协议很多时候无法满足于我们的需求。这会,Socket对于我们来说就非常实用了。下面是本次学习的笔记。主要分异常类型、交互原理、Socket、ServerSocket、多线程这几个方面阐述。


 


异常类型
在了解Socket的内容之前,先要了解一下涉及到的一些异常类型。以下四种类型都是继承于IOException,所以很多之后直接弹出IOException即可。
UnkownHostException:      主机名字或IP错误
ConnectException:        服务器拒绝连接、服务器没有启动、(超出队列数,拒绝连接)
SocketTimeoutException:      连接超时
BindException:          Socket对象无法与制定的本地IP地址或端口绑定
 
交互过程


Socket与ServerSocket的交互,下面的图片我觉得已经说的很详细很清楚了。


 
Socket
构造函数
Socket()


Socket(InetAddress address, int port)throws UnknownHostException, IOException
Socket(InetAddress address, int port, InetAddress localAddress, int localPort)throws IOException
Socket(String host, int port)throws UnknownHostException, IOException
Socket(String host, int port, InetAddress localAddress, int localPort)throws IOException
 
除去第一种不带参数的之外,其它构造函数会尝试建立与服务器的连接。如果失败会抛出IOException错误。如果成功,则返回Socket对象。
InetAddress是一个用于记录主机的类,其静态getHostByName(String msg)可以返回一个实例,其静态方法getLocalHost()也可以获得当前主机的IP地址,并返回一个实例。Socket(String host, int port, InetAddress localAddress, int localPort)构造函数的参数分别为目标IP、目标端口、绑定本地IP、绑定本地端口。
 
Socket方法
getInetAddress();      远程服务端的IP地址
getPort();          远程服务端的端口
getLocalAddress()      本地客户端的IP地址
getLocalPort()        本地客户端的端口
getInputStream();     获得输入流
getOutStream();      获得输出流
值得注意的是,在这些方法里面,最重要的就是getInputStream()和getOutputStream()了。
 
Socket状态
isClosed();            //连接是否已关闭,若关闭,返回true;否则返回false
isConnect();      //如果曾经连接过,返回true;否则返回false
isBound();            //如果Socket已经与本地一个端口绑定,返回true;否则返回false
如果要确认Socket的状态是否处于连接中,下面语句是很好的判断方式。
boolean isConnection=socket.isConnected() && !socket.isClosed();   //判断当前是否处于连接
 


半关闭Socket
很多时候,我们并不知道在获得的输入流里面到底读多长才结束。下面是一些比较普遍的方法:
自定义标识符(譬如下面的例子,当受到“bye”字符串的时候,关闭Socket)
告知读取长度(有些自定义协议的,固定前几个字节表示读取的长度的)
读完所有数据
当Socket调用close的时候关闭的时候,关闭其输入输出流
 
ServerSocket
构造函数
ServerSocket()throws IOException
ServerSocket(int port)throws IOException
ServerSocket(int port, int backlog)throws IOException
ServerSocket(int port, int backlog, InetAddress bindAddr)throws IOException
 
注意点:
1. port服务端要监听的端口;backlog客户端连接请求的队列长度;bindAddr服务端绑定IP
2. 如果端口被占用或者没有权限使用某些端口会抛出BindException错误。譬如1~1023的端口需要管理员才拥有权限绑定。
3. 如果设置端口为0,则系统会自动为其分配一个端口;
4. bindAddr用于绑定服务器IP,为什么会有这样的设置呢,譬如有些机器有多个网卡。
5. ServerSocket一旦绑定了监听端口,就无法更改。ServerSocket()可以实现在绑定端口前设置其他的参数。
 
单线程的ServerSocket例子
复制代码
public void service(){
    while(true){
        Socket socket=null;
        try{
            socket=serverSocket.accept();//从连接队列中取出一个连接,如果没有则等待
            System.out.println("新增连接:"+socket.getInetAddress()+":"+socket.getPort());
            ...//接收和发送数据
        }catch(IOException e){e.printStackTrace();}finally{
            try{
                if(socket!=null) socket.close();//与一个客户端通信结束后,要关闭Socket
            }catch(IOException e){e.printStackTrace();}
        }
    }
}
复制代码
 


多线程的ServerSocket
多线程的好处不用多说,而且大多数的场景都是多线程的,无论是我们的即时类游戏还是IM,多线程的需求都是必须的。下面说说实现方式:
主线程会循环执行ServerSocket.accept();
当拿到客户端连接请求的时候,就会将Socket对象传递给多线程,让多线程去执行具体的操作;
实现多线程的方法要么继承Thread类,要么实现Runnable接口。当然也可以使用线程池,但实现的本质都是差不多的。
 
这里举例:
下面代码为服务器的主线程。为每个客户分配一个工作线程:
复制代码
public void service(){
    while(true){
        Socket socket=null;
        try{
            socket=serverSocket.accept();                        //主线程获取客户端连接
            Thread workThread=new Thread(new Handler(socket));    //创建线程
            workThread.start();                                    //启动线程
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}
复制代码
 


当然这里的重点在于如何实现Handler这个类。Handler需要实现Runnable接口:
复制代码
class Handler implements Runnable{
    private Socket socket;
    public Handler(Socket socket){
        this.socket=socket;
    }
    
    public void run(){
        try{
            System.out.println("新连接:"+socket.getInetAddress()+":"+socket.getPort());
            Thread.sleep(10000);
        }catch(Exception e){e.printStackTrace();}finally{
            try{
                System.out.println("关闭连接:"+socket.getInetAddress()+":"+socket.getPort());
                if(socket!=null)socket.close();
            }catch(IOException e){
                e.printStackTrace();
            }
        }
    }
}
复制代码
当然是先多线程还有其它的方式,譬如线程池,或者JVM自带的线程池都可以。这里就不说明了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/451979.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

彻底搞清楚Android中的 Attr

版权声明:本文为sydMobile原创文章,转载请务必注明出处! https://blog.csdn.net/sydMobile/article/details/79978187 相信这个词对于Android开发者来说十分熟悉了,那么你对他到底有多了解呢? 回忆起我刚开始接触Andr…

D. Relatively Prime Graph

Lets call an undirected graph G(V,E)G(V,E) relatively prime if and only if for each edge (v,u)∈E(v,u)∈E GCD(v,u)1GCD(v,u)1 (the greatest common divisor of vv and uu is 11). If there is no edge between some pair of vertices vv and uu then the value of GC…

解决 : org.apache.ibatis.binding.BindingException: Invalid bound statement (not found)

前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到教程。 报错: org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.tanj.mapper.SendDeta…

网络爬虫--19.【Scrapy-Redis实战】分布式爬虫爬取房天下--环境准备

文章目录0. 思路一. 虚拟机Ubuntu0中安装Redis二. 虚拟机Ubuntu1中安装Redis三. Windows服务器上安装Redis四. 安装cmder五. 安装RedisDesktopManager六. 修改Windows中的配置文件redis.windows.conf七. Ubuntu连接Windows上 的Redis服务器-----------------------------------…

开发人员,请爱护你的身体

最近一周身体极度不适,口腔溃疡、嗓子痛、感冒咳嗽、发烧,统统来了一个遍,非常痛苦。所以最近一直关注有关于软件开发人员的身体健康问题的网站、文章。 看了许多文章,在结合自己在这一周之内痛苦的感受,所以才写这样…

tkinter中scale拖拉改变值控件(十一)

scale拖拉改变值控件 使用户通过拖拽改变值 简单的实现: 1 import tkinter2 3 wuya tkinter.Tk() 4 wuya.title("wuya") 5 wuya.geometry("300x2001020") 6 7 8 # 创建对象 9 scale1 tkinter.Scale(wuya, from_0, to100) 10 scale1.pac…

vue+elementUI开发实践问题总结

最近公司项目采用vue,实行前后端分离开发,采用element-ui框架,对于项目中遇到的问题进行记录,便于日后查询。 vueelementui怎样点击table中的单元格触发事件?官方文档是采用的cell-click方式。实际项目中需要在不同的t…

Socket的getInputStream()方法

Socket的getInputStream()方法可以获得网络连接输入,同时返回一个InputStream实例 。

计算机图形学理论(4):缓冲区

本系列根据国外一个图形小哥的讲解为本,整合互联网的一些资料,结合自己的一些理解。 什么是缓冲区? 缓冲区是保存某些数据的临时存储空间。 为什么我们需要缓冲区?原因很简单,当数据量很大时,因为计算机无…

解决:Every derived table must have its own alias

前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到教程。 报错: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Every derived table must have its own alias 解决&…

网络爬虫--20.【Scrapy-Redis实战】分布式爬虫获取房天下--代码实现

文章目录一. 案例介绍二.创建项目三. settings.py配置四. 详细代码五. 部署1. windows环境下生成requirements.txt文件2. xshell连接ubuntu服务器并安装依赖环境3. 修改部分代码4. 上传代码至服务器并运行一. 案例介绍 爬取房天下(https://www1.fang.com/&#xff…

同一台电脑安装python2python3

【安装之前,先了解一下概念】 python是什么? Python是一种面向对象的解释型计算机程序设计语言,由荷兰人Guido van Rossum于1989年发明,第一个公开发行版发行于1991年。 Python是纯粹的自由软件, 源代码和解释器CPytho…

程序员的常见健康问题

其实这些问题不仅见于程序员,其他长期经常坐在电脑前的职场人士(比如:网络编辑、站长等),都会有其中的某些健康问题。希望从事这些行业的朋友,对自己的健康问题,予以重视。以下是全文。 我最近…

Java中BufferedReader和InputStreamReader

BufferedReader 类BufferedReader 由Reader类扩展而来,提供通用的缓冲方式文本读取,而且提供了很实用的readLine,读取一个文本行,从字符输入流中读取文本,缓冲各个字符,从而提供字符、数组和行的高效读取。…

网络爬虫--21.Scrapy知识点总结

文章目录一. Scrapy简介二. Scrapy架构图三. Scrapy框架模块功能四. 安装和文档五. 创建项目六. 创建爬虫一. Scrapy简介 二. Scrapy架构图 三. Scrapy框架模块功能 四. 安装和文档 中文文档:https://scrapy-chs.readthedocs.io/zh_CN/latest/intro/tutorial.html …

Spring 定时任务的几种实现

前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到教程。 近日项目开发中需要执行一些定时任务,比如需要在每天凌晨时候,分析一次前一天的日志信息,借此机会整…

trie树(字典树)

trie树学习 学习trie树 转载于:https://www.cnblogs.com/cjoierljl/p/9317023.html

Vue 教程第四篇—— Vue 实例化时基本属性

实例元素 el 实例元素指的是 Vue 实例化时编译的容器元素&#xff0c;或者说是 Vue 作用的元素容器 <div id"app"></div> var vm new Vue({el: #app}) 也可以为实例元素指定其它选择器 <div class"app"></div> var vm new Vue({…

Ubuntu将在明年推出平板及手机系统

4月26日下午消息&#xff0c;知名Linux厂商Canonical今天正式发布Ubuntu 12.04版开源操作系统。Ubuntu中国首席代表于立强透露&#xff0c;针对平板电脑的Ubuntu操作系统将在明年推出。 Ubuntu 12.04版开源操作系统发布 Ubuntu操作系统是一款开源操作系统&#xff0c;主要与OE…