Socket-3 续
实现客户端之间的群聊和私聊.
客户端 Client3:
创建一个客户端:
1:向服务器发送数据
2:接受服务器发送的数据
package v34;
public class Client {
/*属性:socket*/
private Socket socket;
public Client(){
try {
socket = new Socket("localhost",8088);
} catch (Exception e) {
e.printStackTrace();
}
}
public void start(){//获取服务端发送来的数据
try {
/*创建线程对象,获取服务端发送来的数据*/
Thread t = new GetServerInfoHandler(socket);
t.start();
连接后:通信已经建立,通过Socket对象获取输出流进行信息传递
OutputStream os = socket.getOutputStream();
PrintWriter pw =
new PrintWriter(
new OutputStreamWriter(os,"utf-8"),true);
Scanner sc = new Scanner(System.in);
System.out.println("请注册昵称:");
String nickName = sc.next();
pw.println(nickName);
System.out.println("欢迎进入聊天室:");
while(true){
String input = sc.next();
pw.println(nickName+":"+input);
pw.flush();
}
} catch (Exception e) {
e.printStackTrace();
}finally{
try {
System.out.println("您已经下线");
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//定义一个内部类对象--线程,就是处理客户端接收服务端发送来的数据
class GetServerInfoHandler extends Thread{
private Socket socket;
public GetServerInfoHandler(Socket socket){
this.socket = socket;
}
public void run(){
try {
//通过socket对象获取输入流,接受服务端发送的数据
InputStream is = socket.getInputStream();
BufferedReader br =
new BufferedReader(
new InputStreamReader(is,"utf-8"));
String line = "";
while((line=br.readLine())!=null){
System.out.println(line);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
Client c = new Client();
c.start();
}
}
OutputStream os = socket.getOutputStream();
PrintWriter pw =
new PrintWriter(
new OutputStreamWriter(os,"utf-8"),true);
Scanner sc = new Scanner(System.in);
System.out.println("请注册昵称:");
String nickName = sc.next();
pw.println(nickName);
System.out.println("欢迎进入聊天室:");
while(true){
String input = sc.next();
pw.println(nickName+":"+input);
pw.flush();
}
} catch (Exception e) {
e.printStackTrace();
}finally{
try {
System.out.println("您已经下线");
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//定义一个内部类对象--线程,就是处理客户端接收服务端发送来的数据
class GetServerInfoHandler extends Thread{
private Socket socket;
public GetServerInfoHandler(Socket socket){
this.socket = socket;
}
public void run(){
try {
//通过socket对象获取输入流,接受服务端发送的数据
InputStream is = socket.getInputStream();
BufferedReader br =
new BufferedReader(
new InputStreamReader(is,"utf-8"));
String line = "";
while((line=br.readLine())!=null){
System.out.println(line);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
Client c = new Client();
c.start();
}
}
服务端Server3
完成任务:
1:接受客户端发送的数据
2: 将数据返回给客户端
package v34;
public class Server {
private ServerSocket server;
/**属性:allOut*/
//使用Map存服务端所获取的客户端的输出流
// key-value key:nickname value:pw
private Map<String,PrintWriter> allOut;
public Server(){
try {
server = new ServerSocket(8088);
allOut = new HashMap<String,PrintWriter>();
} catch (Exception e) {
e.printStackTrace();
}
}
// 发送信息给所有的客户端:
// public void sendMessage(String message){
// for(PrintWriter pw:allOut){
// pw.println(message);
// pw.flush();
// }
// }
/**群聊:遍历map*/
public void sendMessage(String message){
Set<String> keys = allOut.keySet();
for(String key:keys){
PrintWriter pw = allOut.get(key);
//得到每个输出流pw.println(message);
//每个流都发送同样的消息
pw.flush();
}
}
/**私聊:*/
public void sendToOne(String message,String nickName){
if(nickName!=null&&nickName.length()>0){
if(allOut.containsKey(nickName)){
PrintWriter pw =allOut.get(nickName);
pw.println(message);
pw.flush();
}else{
sendMessage(message);
}
}
}
/** * 保存所有的向客户端发送数据的输出流对象
* @param pw:向客户端发送数据的输出流对象。
*/
// public void savePW(PrintWriter pw){
// if(pw!=null){
// allOut.add(pw);
// }
// }
/** * 将服务端获取的客户端的输出流进行保存
*/public void savePW(String nickName,PrintWriter pw){
if(nickName!=null&&nickName.length()>0)
{allOut.put(nickName, pw);}}
// public void deletePW(PrintWriter pw){
// if(pw!=null){
// allOut.remove(pw);
// }// }
/** * 客户端下线,删除Map中的key-value。 */
public void deletePW(String nickName){
if(nickName!=null&&nickName.length()>0){
allOut.remove(nickName);}}
public void start(){try {
/*循环接受多个客户端的请求连接*/
while(true){System.out.println("--等待连接--");
/* * 通过accept()获取客户端的连接请求
* 此方法有阻塞效果。当没有发现连接请求时
* 会一直阻塞在这里。不会执行后续的程序。
*/Socket socket = server.accept();
/*
* 获取客户端的信息
*/int port = socket.getPort();
InetAddress add = socket.getInetAddress();
String name = add.getHostName();
System.out.println("客户端:"+name+",端口号:"+port+"已经连接上服务器");
Thread t = new GetClientInfoHandler(socket);
t.start();}}
catch (Exception e) {e.printStackTrace();}}
/** * 定义一个内部类--线程。
* 处理每一个客户端的信息。
* 接受客户端的信息和发送会给客户端
* 需要流,socket提供的。
*/
class GetClientInfoHandler extends Thread{
private Socket socket;
public GetClientInfoHandler(Socket socket){this.socket = socket;}
public void run(){
PrintWriter pw = null;String nickName = "";
try {
/*通过socket对象获取输入流,
* 处理客户端发送过来的数据 *
*/
InputStream is = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is,"utf-8"));
/* * 通过Socket对象获取输出流
* 作用是将收到的数据写回给客户端
*/
OutputStream os = socket.getOutputStream();
pw = new PrintWriter(new OutputStreamWriter(os,"utf-8"),true);
/* * 将向此客户端发送信息的输出流,保存在服务器 */
nickName = br.readLine();savePW(nickName,pw);
System.out.println("在线人数:"+allOut.size());
String line = "";
/*将从客户端读取的数据,发回给客户端 * 是一个循环操作 * */
while((line=br.readLine())!=null){
/*分析line是否是私聊部分*/
if(line.contains("@")&&line.contains("#")){
//进行截取int start = line.indexOf("@");
int end = line.indexOf("#");
String nick=line.substring(start+1, end);
sendToOne(line.substring(end+1),nick);}
else{sendMessage(line);}}}
catch (Exception e) {
e.printStackTrace();
}
finally{deletePW(nickName);
sendMessage(nickName+"已经下线了");
System.out.println("当前在线人数:"+allOut.size());
try {socket.close();}
catch (IOException e) {
e.printStackTrace();}}}}
public static void main(String[] args) {
Server server = new Server();server.start();
}
}