使用ServerSocket、Socket创建一个简单的服务聊天程序
2015-09-07 23:25
856 查看
使用ServerSocket创建TCP服务器端:
在两个实心实体没有建立虚拟链路之前,必须有一个通信实体先做出“主动姿态”,主动接收来自其他通信实体的连接请求。
ServerSocket在Java中能接收到其他通信的连接请求,ServerSocket对象用于监听来自客户端Socket的连接请求,ServerSocket使用完毕后再使用它的close()方法将ServerSocket关闭,一般服务端要接收好多个客户端的连接请求,所以程序中通常会用while循环不断的调用ServerSocket的accept()方法来接收客户端的请求。
上面的客户端通信就是用Socket来连接到服务端的,经常用的就是
因为本地主机只有一个IP地址,所有使用这个比较方便简单
本地IP地址使用的是127.0.0.1,这个还是比较特殊的,它总是代表着本机的IP地址哈。
当客户端和服务端产生了对应的Socket后,程序也就不再区分什么服务器端和客户端,直接通过各自的Socket进行通信。
基于这个可以做一个简单的通信代码,当你连接上服务端后,服务器会向所有在线的客户端广播*******on Line,然后你无论说什么,服务端就像一个大喇叭给你广播出去给所有客户端看。
程序写的有点繁琐,上面那个是客户端的代码,下面这个是服务端的代码:
在两个实心实体没有建立虚拟链路之前,必须有一个通信实体先做出“主动姿态”,主动接收来自其他通信实体的连接请求。
ServerSocket在Java中能接收到其他通信的连接请求,ServerSocket对象用于监听来自客户端Socket的连接请求,ServerSocket使用完毕后再使用它的close()方法将ServerSocket关闭,一般服务端要接收好多个客户端的连接请求,所以程序中通常会用while循环不断的调用ServerSocket的accept()方法来接收客户端的请求。
ServerSocket server=new ServerSocket(8088); //当接收到客户端的连接请求时,服务端就会产生一个Socket //为了让服务端不断的接收来自客户端的请求,所以都是用while循环 while(true){ Socket s=server.accept(); }
上面的客户端通信就是用Socket来连接到服务端的,经常用的就是
Socket socket=new Socket(InetAddress/String remoteAddress,int port);
因为本地主机只有一个IP地址,所有使用这个比较方便简单
本地IP地址使用的是127.0.0.1,这个还是比较特殊的,它总是代表着本机的IP地址哈。
当客户端和服务端产生了对应的Socket后,程序也就不再区分什么服务器端和客户端,直接通过各自的Socket进行通信。
基于这个可以做一个简单的通信代码,当你连接上服务端后,服务器会向所有在线的客户端广播*******on Line,然后你无论说什么,服务端就像一个大喇叭给你广播出去给所有客户端看。
package Chat; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.net.Socket; import java.util.Scanner; /** * 客户端 * * Java.net.Socket * 封装了TCP协议的Socket * 通过它来连接服务端的ServerSocket并创建输入输出流来与服务端通信 * @author Administrator * */ public class Client { private Socket socket; /* * 构造方法,用来初始化客户端 * 构造方法常用来初始化对象属性等操作 */ public Client(){ try { /* * 初始Socket时需要传入两个参数 * 1.服务端IP地址 * 2.服务端端口号 * * 首先要清楚: * 通讯是客户端计算机上的一个客户端应用程序与服务端计算机(俗称服务器)上的一个服务端 * 应用程序之间的通讯 * * IP地址的作用是让我们通过网络可以找到服务器,而端口可以让我们找到运行在服务器上的服务端 * 应用程序。 * * 创建Socket实例的过程就是与服务端连接的过程,若可以成功与服务器连接上,则会创建Socket * 实例,否则构造方法会抛出异常。 */ System.out.println("正在尝试连接服务端……"); socket=new Socket("localhost",8088); System.out.println("与服务端连接成功"); } catch (Exception e) { e.printStackTrace(); } } /* * 客户端开始工作的方法 */ public void start(){ try { /* * 当客户端启动后,就启动接收服务端发送过来消息的线程 */ GetServerMessageHandler handler=new GetServerMessageHandler(); new Thread(handler).start(); /* * OutputStream getOutputStream() * Socket提供了该方法,用来获取输出流来向服务端发送数据。 */ Scanner scan=new Scanner(System.in); OutputStream out=socket.getOutputStream(); OutputStreamWriter osw=new OutputStreamWriter(out,"UTF-8"); PrintWriter pw=new PrintWriter(osw,true); System.out.println("客户端输入信息:"); while(true){ String message=scan.next(); pw.println(message); } } catch (Exception e) { e.printStackTrace(); } } public static void main(String[] args) { Client client = new Client(); client.start(); } /** * 由于接收服务端发送来的消息,与我们给服务端发送消息没有必然关系,所以两者应当在两个不同 * 线程上完成,各做各的,互不干涉。 * @author Administrator * */ private class GetServerMessageHandler implements Runnable{ public void run(){ try { /* * 该线程的职责就是读取服务端发送过来的每一条消息,并输出到控制台 */ InputStream in=socket.getInputStream(); InputStreamReader isr=new InputStreamReader(in,"utf-8"); BufferedReader br=new BufferedReader(isr); String message=null; while((message=br.readLine())!=null){ System.out.println("服务器说:"+message); } } catch (Exception e) { } } } }
程序写的有点繁琐,上面那个是客户端的代码,下面这个是服务端的代码:
package Chat; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; import java.util.ArrayList; import java.util.List; /** * 聊天室服务端 * * java.net.ServerSocket * ServerSocket是运行在服务端的,其作用是向系统申请服务端端口,以便监听该端口,等待客户端的连接, * 一旦一个客户端连接,就会创建一个Socket与该客户端进行通信。 * @author Administrator * */ public class Server { private ServerSocket server;//ServerSocket对象用于监听来自客户端的Socket连接, //ServerSocket包含一个 监听来自客户端连接请求的方法 //存放所有客户端输出流的集合,用于广播信息 private List<PrintWriter> allOut; public Server(){ try { allOut=new ArrayList<PrintWriter>(); /* * 初始化ServerSocket的同时需要指定服务端口,该端口不能与当前系统使用TCP协议的 * 其他程序申请的端口冲突,否则会抛出端口被占用异常 */ server = new ServerSocket(8088); } catch (Exception e) { e.printStackTrace(); } } private synchronized void addOut(PrintWriter pw){ allOut.add(pw); } private synchronized void removeOut(PrintWriter pw){ allOut.remove(pw); } private synchronized void sendMessageToAllClient(String m){ for(PrintWriter pw:allOut){ pw.println(m); } } //服务端开始工作的方法 public void start(){ try { /* * Socket accept() * ServerSocket提供该方法用来监听打开服端口(8088),该方法是一个阻塞方法, * 直到一个客户端尝试连接才会解除阻塞,并创建一个Socket与刚连接的客户端进行通讯。 * * accept方法每次调用都会等待一个客户端的连接,所以若希望让若干个客户端连接,就需要多次 * 调用该方法,来分别获取对应这些客户端 * 的socket与他们通讯。 */ while(true){ System.out.println("等待客户端连接……"); Socket socket=server.accept(); System.out.println("一个客户端连接了!"); /** * 当一个客户端连接后,启动一个线程,来负责与该客户端交互 */ ClientHandler handler=new ClientHandler(socket); new Thread(handler).start(); } } catch (Exception e) { e.printStackTrace(); } } public static void main(String[] args) { Server server=new Server(); server.start(); } /** * * 该线程用来与一个指定的客户端进行交互 * 每当一个客户端连接服务端后,都会启动当前线程来负责与之交互工作。 */ private class ClientHandler implements Runnable{ private Socket socket; //客户端地址信息 private String host; public ClientHandler(Socket socket){ this.socket=socket; //通过socket可以得知远端计算机信息 InetAddress address=socket.getInetAddress(); host=address.getHostAddress(); } public void run(){ PrintWriter pw=null; try { /* * 通过客户端的Socket获取输出流,以便将消息发送给客户端 */ OutputStream out=socket.getOutputStream(); OutputStreamWriter osw=new OutputStreamWriter(out,"UTF-8"); pw=new PrintWriter(osw,true); //共享该客户端的输出流 addOut(pw); //广播该用户上线 sendMessageToAllClient(host+"onLine"); /* * InputStream getInputStream() * Socket提供的该方法用来获取输入流,读取远端计算机发送过来的数据 */ InputStream in=socket.getInputStream(); InputStreamReader isr=new InputStreamReader(in,"utf-8"); BufferedReader br=new BufferedReader(isr); String message=null; /* * 当我们使用BufferedReader读取来自远端计算机发送过来的内容时,由于远端计算机的操作系统不同, * 当他们断开连接时,这里readline方法的结果也不同: * 当远端计算机操作系统是Windows时,若断开连接,这里的readline方法直接会抛出异常。 * 当远端计算机操作系统是Linux时,若断开连接,这里的readline方法返回NULL。 */ while((message=br.readLine())!=null){ sendMessageToAllClient(host+"说:"+message); } } catch (Exception e) { e.printStackTrace(); }finally{ /* * 当该客户端与服务端断开时,应当将该客户端的输出流从共享集合删除。 */ allOut.remove(pw); /** * 无论是Linux的客户端还是Windows的客户端,当与服务器断开连 * 接后,都应当将与该客户端交互的 socket关闭,来释放底层资源。 */ if(socket!=null){ try { socket.close(); } catch (IOException e) { e.printStackTrace(); } } } } } }
相关文章推荐
- Fedora22远程连接win8.1一路遇到的问题与解决方法
- JMX的Hello World
- CMakeLists 文件
- nginx 测试
- 【C++学习笔试】-模板
- 条款14:在资源管理类中心copying行为(Think carefully about copying behavior in resource-manage classes)
- bash 环境变量
- Uva-10817 Headmaster's Headache
- TCP 回顾
- Lua Interface基础使用
- Android通过注解来初始化控件
- uva 10129 单词
- uva 1494 - Qin Shi Huang's National Road System(最小生成树)
- redis常用命令笔记
- ActiveMQ in action 前言
- 【一些事晚报】苹果iPhone 6S将逼死iPad Mini
- 第一周-A Simple Java Program
- Content Providers的步骤,来自官网文档
- 配置/etc/sysconfig/network-script/ifcfg-eth0
- HDU 2097