仿QQ大战—服务器的搭建(ServerSocket)
ServerSocket(服务器):
ServerSocket是JAVA中提供的用于建立服务器的类; 在客户/服务器通信模式中, 服务器端需要创建监听端口的 ServerSocket, ServerSocket 负责接收客户连接请求.
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
在以上构造方法中, 参数 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-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)的更多相关文章
- 仿QQ大战—界面篇
之前在<仿QQ大战-服务器的搭建(ServerSocket)>中实现了服务器的搭建,以及一个简单地传递数据的实现,现在就是来实现类似与QQ聊天通信的功能.首先是界面的实现: 首先:服务器和 ...
- Socket实现仿QQ聊天(可部署于广域网)附源码(2)-服务器搭建
1.前言 这是本系列的第二篇文章,第一篇文章得到了很多朋友们的支持,在这里表示非常的感谢.对于这一系列文章需要补充的是这只是一篇入门级别的Socket通信文章,对于专业人员来说完全可以跳过.本文只介绍 ...
- GFF高仿QQ客户端及服务器
一.GFF简介 GFF是仿QQ界面,通信基于SAEA.MessageSocket.SAEA.Http.SAEA.MVC实现包含客户端和服务器的程序,源码完全公开,项目源码地址:https://gith ...
- iOS传感器集锦、飞机大战、开发调试工具、强制更新、Swift仿QQ空间头部等源码
iOS精选源码 飞机大作战 MUPhotoPreview -简单易用的图片浏览器 LLDebugTool是一款针对开发者和测试者的调试工具,它可以帮... 多个UIScrollView.UITable ...
- Socket实现仿QQ聊天(可部署于广域网)附源码(1)-简介
1.前言 本次实现的这个聊天工具是我去年c#程序设计课程所写的Socket仿QQ聊天,由于当时候没有自己的服务器,只能在机房局域网内进行测试,最近在腾讯云上买了一台云主机(本人学生党,腾讯云有个学生专 ...
- < JAVA - 大作业(2)仿qq即时通讯软件 >
< JAVA - 大作业(2)仿qq即时通讯软件 > 背景 JAVA上机大作业:设计一个仿qq即时通讯软件 任务简要叙述:设计一款仿QQ的个人用户即时通讯软件,能够实现注册,登陆,与好友聊 ...
- python服务器环境搭建(1)——本地服务器准备
去年十月底到新公司上班,由于公司旧系统存在各种问题同时不便于扩展,而公司领导对17年寄予很大的期望,用户量.收入要上一个新台阶,我经过全面评估后,决定全部用python重构过,开发一个基于微服务架构的 ...
- python服务器环境搭建(2)——安装相关软件
在上一篇我们在本地的虚拟服务器上安装好CentOS7后,我们的python web服务.自定义的python service或python脚本需要在服务器上运行,还需要在服务器安装各种相关的软件才行, ...
- 仿QQ空间和微信朋友圈,高解耦高复用高灵活
先看看效果: 用极少的代码实现了 动态详情 及 二级评论 的 数据获取与处理 和 UI显示与交互,并且高解耦.高复用.高灵活. 动态列表界面MomentListFragment支持 下拉刷新与上拉加载 ...
随机推荐
- IOS开发之Bug--使用KVC的易错情况
1.其实某些角度而言KVC是一个破坏封装又暴力的做法,而我已经两次因为KVC而导致应用程序出现闪退的情况. 场景:1.使用KVC修改某一个UIView的属性,比如width. 2.在viewWi ...
- Hadoop系列教程<一>---Hadoop是什么呢?
Hadoop适合应用于大数据存储和大数据分析的应用,适合于服务器几千台到几万台的集群运行,支持PB级的存储容量.Hadoop典型应用有:搜索.日志处理.推荐系统.数据分析.视频图像分析.数据保存等.但 ...
- 内嵌iframe
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Index.aspx.cs& ...
- Oracle索引梳理系列(六)- Oracle索引种类之函数索引
版权声明:本文发布于http://www.cnblogs.com/yumiko/,版权由Yumiko_sunny所有,欢迎转载.转载时,请在文章明显位置注明原文链接.若在未经作者同意的情况下,将本文内 ...
- Yii2 使用a标签发送post请求
<?= Html::a('text', 'url', [ 'data' => [ 'method' => 'post', 'params' => [ 'params_key' ...
- Media Queries 详解
Media Queries直译过来就是“媒体查询”,在我们平时的Web页面中head部分常看到这样的一段代码: <link href="css/reset.css" rel ...
- MMORPG大型游戏设计与开发(服务器 游戏场景 事件)
今天第星期天,知识是永远是学习不完的,所以今天这部分算比较轻松,同时也希望大家会有一个好的周末.场景事件即场景的回调,和别的事件一样是在特定的条件下产生的,前面也介绍过场景的各种事件,今天详细的说一说 ...
- postman使用之五:Runner的使用
1.首先在postman新建要批量运行的接口文件夹,新建一个接口,并设置好全局变量. 2.然后在Test里面设置好要断言的方法 如: tests["Status code is 200&qu ...
- js事件绑定及深入
学习要点: 1.传统事件绑定的问题2.W3C事件处理函数3.IE事件处理函数4.事件对象的其他补充 事件绑定分为两种:一种是传统事件绑定(内联模型,脚本模型),一种是现代事件绑定(DOM2级模型).现 ...
- BZOJ1497: [NOI2006]最大获利[最小割 最大闭合子图]
1497: [NOI2006]最大获利 Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 4375 Solved: 2142[Submit][Status] ...