ServerSocket(服务器):

ServerSocket是JAVA中提供的用于建立服务器的类; 在客户/服务器通信模式中, 服务器端需要创建监听端口的 ServerSocket, ServerSocket 负责接收客户连接请求.

ServerSocket类提供了四个构造方法:

  1. ServerSocket() throws IOException
  2. ServerSocket(int port) throws IOException
  3. ServerSocket(int port, int backlog) throws IOException
  4. ServerSocket(int port, int backlog, InetAddress bindAddr) throws IOException

在以上构造方法中, 参数 port 指定服务器要绑定的端口( 服务器要监听的端口), 参数 backlog 指定客户连接请求队列的长度, 参数 bindAddr 指定服务器要绑定的IP 地址.

1.建立单线程服务器

现在我们用第二个方法创建一个服务器,这是要实现聊天通信第一步。

	public void init(int port) {
try {
// 创建一个绑定在指定端口上的服务器对象;
ServerSocket server = new ServerSocket(port);
} catch (IOException e) {
e.printStackTrace();
} finally { }
}

调用该方法的时候,传入我们的端口号,而端口号是在0到65535之间。而当我们输入大于这个范围的数的时候,就会报出下面这个异常,越界;

另外还需要注意的是如果代码抛出 IOException, 更确切地说, 是抛出 BindException,(是 IOException 的子类),那么 一般是由以下原因造成的:

    1. 端口已经被其他服务器进程占用;
    2. 在某些操作系统中, 如果没有以超级用户的身份来运行服务器程序, 那么操作系统不允许服务器绑定到 1-1023 之间的端口。

第二步:建立服务器之后,我们就要通过服务器获取连接在它上面的客服端;

  	try {
Socket client=server.accept();
} catch (IOException e) {
e.printStackTrace();
}

我们看一下accept方法,在该方法中,会抛出一个IO异常。他监听服务器与客户端直接的连接,并且接收它,当没有连接的时候,他会进入阻塞状态,等待用户连接;

* Listens for a connection to be made to this socket and accepts
* it. The method blocks until a connection is made.

然后,第三步:在我们接收到客户端之后,我们就可以来获取客户端的输入和输出流,进行数据的读取。

  //从连接对象上获取数据;
OutputStream os=client.getOutputStream();
InputStream ips=client.getInputStream();

这样我们就可以输入和输出数据:

例如:我们对每一个连接进来的客户端发送,“hello!”

os.write("hello!".getBytes());

我们也可以从客户端读取一个字节;然后把它输出:

  char i=(char)ips.read();
System.out.println(i+"");

写到这里我们运行一下,只要端口没有被占用的话,结果就很顺利。

客户端就可以通过我们的端口连接上服务器了。运行程序,然后在电脑中的cmd命令提示符,输入 telnet + IP地址(或者localhost(表示本机))+ 端口号可以连接上我们的服务器了;

这时,我们的服务器可以做的事情就是乡客户端发送一个“hello!”,然后读取一个字符,然后,我们的服务器就马上关闭了。

那么,我们怎么样才能接收一个字符串,并且客户端能够一直输入?

2.服务器接收字符串:

方法一:加上结束符;客户端和服务器之间商量一个通信协议,比如说,客户端每一次输出都在最后加上一个’/’符号,然后在服务端这边我们就可以判断,当读到一个’/’的时候,我就停止接收;也就代表一句话说完了。如下:

 StringBuffer buffer = new StringBuffer();//可变字符串

char ch = (char) in.read(); //in为我们的输入流;

//不断地读取字符,添加到StringBuffer里面,直到我们读到‘/’结束符

while (ch != '/') {

buffer.append(ch);

ch = (char) in.read();

}

System.out.println(buffer);//输出我们的字符串;

方法二:

运用字符流,在BufferedReader中有读取一行的方法:

 try {

	  InputStreamReader isr = new InputStreamReader(client.getInputStream());
OutputStreamWriter osw = new OutputStreamWriter(client.getOutputStream()); BufferedReader buf = new BufferedReader(isr);
BufferedWriter bufw = new BufferedWriter(osw); bufw.write("欢迎连接服务器");
bufw.flush();// 冲洗刷新;
while (isStop) {
String str = buf.readLine();
if (str == null)
break;// 如果对到的数据为NUll,则跳出循环结束线程;
System.out.println(str); }
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
client.close();
} catch (IOException e) {
e.printStackTrace();
}
}

方法三:

每一客户端发送消息之前,先发送他要发送的长度,然后我们再发送要发送的消息;然后服务器,根据这个数量再来接收我们要接收的消息;

实现了获取一个字符串,那么,客户端要想一直发送消息的话,我们只要,把接收消息的代码放入一个while(true){}语句里面。那么我们的就可以一直接收到客户端的消息了,直到客户端关闭。

代码如下(第一种方法):

while (true) {

StringBuffer buffer = new StringBuffer();//可变字符串

char ch = (char) in.read();

//不断地读取字符,添加到StringBuffer里面,直到我们读到‘/’结束符

while (ch != '/') {

buffer.append(ch);

ch = (char) in.read();

}
System.out.println(buffer); }

然后在来运行我们的代码,会发现我们的客户端送到了,服务器发来的“hello!”,并且我们也可以不断地接收。但是......问题又来了。但我们这个时候再去开启一个新的客户端连接的时候,他好像看上去是跳转连接了,但是却并没有收到我们的服务器发来的消息,更加不能向我们的服务器发消息了。那么我们再加上一个while(true){}循环,让服务器不断地接收客户端。是不是就可以了?

我们看一下整段代码:

public void init(int port) {
try {
// 创建一个绑定在指定端口上的服务器对象;
ServerSocket server = new ServerSocket(port);
while(true){ //该循环只是执行了一次,因为内循环一直没有停止
Socket client = server.accept();
OutputStream out = client.getOutputStream();// 输出流
InputStream in = client.getInputStream();// 输入流;
out.write("欢迎连接服务器".getBytes());
while (true) {//内循环
//可变字符串
StringBuffer buffer = new StringBuffer();
char ch = (char) in.read();
//不断地读取字符,添加到StringBuffer里面,直到我们读到‘/’结束符
while (ch != '/') {
buffer.append(ch);
ch = (char) in.read();
}
System.out.println(buffer);
}
}
} catch (IOException e) {
e.printStackTrace();
} finally { }
}

虽然,代码简单地看起来,像是服务器会一直接收客户端,,然后通过输入输出流输出和接收数据。但是很快我们就会发现,在我们接收输入数据的时候内循环会一直进行,不会停止,所以就算我们把那个外边的循环while(true){}加上,外边的循环也只能执行一次。

3.开启多线程服务器

那么怎么样才能让外循环有作用呢?这时,我们就考虑加上一个线程,把内循环放入线程中,也就是服务器每连接上一个客户端的时候我们都去开启一个线程,让线程去接收输入输出流,处理输入输出。 如下:

public void init(int port){

	try {
//创建一个绑定在指定端口上的服务器对象;
server=new ServerSocket(port);
System.out.println("服务器创建成功,端口号为:"+port);
while(true){
Socket client=server.accept();
//开启线程,并把我们的端口传入线程里面;
MyThread mythread=new MyThread(client);
mythread.start();
}
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
server.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

而我们的线程里面,就是去获取我们的输入输出流,然后不断地进行输出输入;

代码如下(这里采用第二中方法,字符流来处理):

@Override
public void run() {
try {
InputStreamReader isr = new InputStreamReader(client.getInputStream());
OutputStreamWriter osw = new OutputStreamWriter(client.getOutputStream());
BufferedReader buf = new BufferedReader(isr);
BufferedWriter bufw = new BufferedWriter(osw);
bufw.write("欢迎连接服务器");
bufw.flush();// 冲洗刷新;
while (isStop) {
String str = buf.readLine();
// 如果对到的数据为NUll,则跳出循环结束线程;
if (str == null)
break;
System.out.println(str);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
client.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

这样,我们的服务器也就可以连接上多个客户端了,并且每一个客户端都能够向他发送消息;

现在,我们来回顾一个整个过程:

整个过程大致就是这样啦!!!!!

仿QQ大战—服务器的搭建(ServerSocket)的更多相关文章

  1. 仿QQ大战—界面篇

    之前在<仿QQ大战-服务器的搭建(ServerSocket)>中实现了服务器的搭建,以及一个简单地传递数据的实现,现在就是来实现类似与QQ聊天通信的功能.首先是界面的实现: 首先:服务器和 ...

  2. Socket实现仿QQ聊天(可部署于广域网)附源码(2)-服务器搭建

    1.前言 这是本系列的第二篇文章,第一篇文章得到了很多朋友们的支持,在这里表示非常的感谢.对于这一系列文章需要补充的是这只是一篇入门级别的Socket通信文章,对于专业人员来说完全可以跳过.本文只介绍 ...

  3. GFF高仿QQ客户端及服务器

    一.GFF简介 GFF是仿QQ界面,通信基于SAEA.MessageSocket.SAEA.Http.SAEA.MVC实现包含客户端和服务器的程序,源码完全公开,项目源码地址:https://gith ...

  4. iOS传感器集锦、飞机大战、开发调试工具、强制更新、Swift仿QQ空间头部等源码

    iOS精选源码 飞机大作战 MUPhotoPreview -简单易用的图片浏览器 LLDebugTool是一款针对开发者和测试者的调试工具,它可以帮... 多个UIScrollView.UITable ...

  5. Socket实现仿QQ聊天(可部署于广域网)附源码(1)-简介

    1.前言 本次实现的这个聊天工具是我去年c#程序设计课程所写的Socket仿QQ聊天,由于当时候没有自己的服务器,只能在机房局域网内进行测试,最近在腾讯云上买了一台云主机(本人学生党,腾讯云有个学生专 ...

  6. < JAVA - 大作业(2)仿qq即时通讯软件 >

    < JAVA - 大作业(2)仿qq即时通讯软件 > 背景 JAVA上机大作业:设计一个仿qq即时通讯软件 任务简要叙述:设计一款仿QQ的个人用户即时通讯软件,能够实现注册,登陆,与好友聊 ...

  7. python服务器环境搭建(1)——本地服务器准备

    去年十月底到新公司上班,由于公司旧系统存在各种问题同时不便于扩展,而公司领导对17年寄予很大的期望,用户量.收入要上一个新台阶,我经过全面评估后,决定全部用python重构过,开发一个基于微服务架构的 ...

  8. python服务器环境搭建(2)——安装相关软件

    在上一篇我们在本地的虚拟服务器上安装好CentOS7后,我们的python web服务.自定义的python service或python脚本需要在服务器上运行,还需要在服务器安装各种相关的软件才行, ...

  9. 仿QQ空间和微信朋友圈,高解耦高复用高灵活

    先看看效果: 用极少的代码实现了 动态详情 及 二级评论 的 数据获取与处理 和 UI显示与交互,并且高解耦.高复用.高灵活. 动态列表界面MomentListFragment支持 下拉刷新与上拉加载 ...

随机推荐

  1. Atitit.木马病毒自动启动-------------win7计划任务的管理

    Atitit.木马病毒自动启动-------------win7计划任务的管理 1. 计划任务的Windows系统中取代AT 的schtasks命令1 2. Win本身的系统计划任务列表1 2.1.  ...

  2. SQL Server 诊断查询-(2)

    Query #13 SQL Server Error Log(FC) -- Shows you where the SQL Server failover cluster diagnostic log ...

  3. Visual Studio 2013 Update 2 RTM 发布

    今天,微软再Visual Studio Blog发布了开放Visual Studio 2013 Update 2 RTM 下载的文章. 原来安装RC版本的同志们可以直接安装,提供在线安装和ISO下载安 ...

  4. mysql中类似indexOf的方法LOCATE()

     LOCATE(substr,str), LOCATE(substr,str,pos) 第一个语法返回substr在字符串str 的第一个出现的位置. 第二个语法返回子符串 substr 在字符串st ...

  5. MySQL插入语句解析

    1.INSERT INTO 最常用简单的插入语句,可以有以下两种用法 1>  INSERT INTO tb_user(id, name, age) VALUES (100022, 'Tom', ...

  6. Asp.Net MVC+BootStrap+EF6.0实现简单的用户角色权限管理6

    接下来先做角色这一板块的(增删改查),首先要新建一个Role控制器,在添加一个RoleList的视图.表格打算采用的是bootstrap的表格. using System; using System. ...

  7. [Java入门笔记] 面向对象编程基础(二):方法详解

    什么是方法? 简介 在上一篇的blog中,我们知道了方法是类中的一个组成部分,是类或对象的行为特征的抽象. 无论是从语法和功能上来看,方法都有点类似与函数.但是,方法与传统的函数还是有着不同之处: 在 ...

  8. Terminate Instance 操作详解 - 每天5分钟玩转 OpenStack(33)

    本节通过日志详细分析 Nova Terminate 操作. Terminate 操作就是删除 instance,下面是 terminate instance 的流程图 向 nova-api 发送请求 ...

  9. 用keytool工具生成签名文件与获取摘要信息

    在Command命命令行模式下: 转到工作目录 执行下面命令: keytool -genkey -v -keystore debug.keystore 最后是生成的文件名,执行该命令后有很多内容要填写 ...

  10. 配置TortoiseSVN客户端, 强制签入前加注释

    正如上篇提到, 总有一些人在签入代码到SVN前没有加注释, 然后, 像这样: 鬼才知道改了什么东西. ①有些人可能就是没有写注释的习惯, ②有些人可能是忘记写注释 && SVN服务端和 ...