Server.java
package socket;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
/**
* 聊天室服务端
* @author 小明
*
*/
public class Server {
/**
* 运行在服务端的ServerSocket主要有两个作用:
* 1:向系统申请服务端口,客户端就是通过这个端口与服务端建立连接的。
* 2:监听服务端口,一旦客户端与服务端建立连接,就会
* 自动创建一个Socket,并通过该Socket与建立连接的
* 客户端进行交互。
*
*/
private ServerSocket server;
public Server()
{
try{
/**
* 实例化ServerSocket的同时要指定向系统申请的服务端口。注意,该端口
* 不能与当前系统其它应用程序申请的端口号一致,
* 否则会抛出端口被占用的异常。
*/
System.out.println("正在启动服务端...");
server = new ServerSocket(8088);
System.out.println("服务端启动完毕!");
}catch(Exception e){
}
}
public void start()
{
try {
while(true)
{
System.out.println("等待客户端连接");
Socket socket = server.accept();
//accept用来感知socket。
System.out.println("一个客户端连接进去了。");
ClientHandler hander = new ClientHandler(socket);
Thread t1 = new Thread(hander);
t1.start();
}
/**
* 准备接受客户端连接
*
* 这是一个阻塞方法。
*一旦调用accpet()方法,服务端阻塞在这里,等着客户端连接了。
*这时当我们启动客户端时,客户端实例化socket,通过IP找到应用程序。
*这时accpet()马上就会有反应。accpet()方法执行完就返回一个socket。
*通过这个socket就可以与刚建立连接的这个客户端进行通讯了。
*客户端创建一个socket,服务端通过accept()接收一个socket。
*这时候就可以进行沟通了。
* 需要处理异常。
*/
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String[] args) {
Server server = new Server();
server.start();
}
/**
* 通过输入流读取远端计算机发送过来的信息时
* br.readLine()方法对于不同系统的客户端断开时的反应不一样
* windows的客户端断开时,会直接抛出异常
* linux的客户端断开时,会返回null
* 该线程任务是负责与指定的客户端进行交互
* @author 小明
*
*/
private class ClientHandler implements Runnable{
private Socket socket;
private String host;
//创建时需要将Socket传入,以便对该客户端交互
public ClientHandler(Socket socket) {
this.socket = socket;
//通过socket获取远端的地址信息
InetAddress address = socket.getInetAddress();
host = address.getHostAddress();
}
@Override
public void run() {
try{
System.out.println("进入了线程,现在正在调用run()方法");
InputStream in = socket.getInputStream();
InputStreamReader isr = new InputStreamReader(in);
BufferedReader br = new BufferedReader(isr);
String message = null;
System.out.println("客户端地址是:" + host);
//System.out.println("尝试输出br.readLine()" + br.readLine());
System.out.println("while最上面的那条语句");
while((message = br.readLine()) != null)
{
System.out.println("读取到了数据");
System.out.println(host + "说" + message);
System.out.println("一个客户端连接了");
}
if(message == null){
System.out.println("message是空的");
}
br.close();
}catch(IOException e){
e.printStackTrace();
}finally{
//br.close();
}
}
}
}
Client.java
package socket;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;
/**
* 聊天室客户端
* @author 小明
*
*/
public class Client {
/**
* 套接字
* 封装了TCP协议的通信细节,让我们可以简单地使用它完成TCP通讯
* Socket连接后提供了两条流,通过两条流的读写操作完成与远端计算机的数据连接
* 完成与远端计算机的数据交换。
*/
private Socket socket;
public Scanner reader;
/**
* 用来初始化客户端
*/
public Client()
{
try {
/**
* 实例化Socket时需要传入两个参数:
* 1:服务端的IP地址
* 2:服务端的端口号
* 通过IP地址可以找到服务端所在的计算机
* 通过端口可以找到运行在服务端计算机上的
* 服务端应用程序
* 注意,实例化Socket的过程就是连接的过程,若
* 连接失败就会抛出异常。
*/
reader = new Scanner(System.in);
System.out.println("正在连接服务端...");
socket = new Socket("localhost", 8088);
System.out.println("与服务端建立连接!");
/**
* 有两个参数,一个是IP地址,一个是端口号
*/
/**
* 所有应用程序在使用网络的时候都要和操作系统申请一个网络端口
*
*/
/**
* 异常要我们自己进行处理,不要抛出
*/
}catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* 写程序时不要过度依赖main方法
* 客户端开始工作的方法
*/
public void start()
{
try{
//socket.getOutputStream();
//打桩
//可以找到代码错的地方。
PrintWriter pw = new PrintWriter(
new BufferedWriter(
new OutputStreamWriter(
socket.getOutputStream())), true);
//pw.write("你好服务端");
//使用上面这条语句是错的,要使用具有自动行刷新的方法
//不要再下意识地写上面那条语句了
// for(int i = 0; i < 10; i++){
// pw.println("你好服务端!" + i);
// }
while(true)
{
String line = reader.nextLine();
pw.println(line);
}
}catch(Exception e){
e.printStackTrace();
}
}
public static void main(String[] args) {
Client client = new Client();
client.start();
}
}