您的位置:首页 > 理论基础 > 计算机网络

java TCP/IP实现简单的多人聊天功能

2015-08-09 11:49 861 查看
TCP/IP是可靠的网络协议,数据的传输需要服务端和客户端之间三次“握手”,比较适合文本等一些可靠性要求高的数据传输,但是它的效率较UDP低。下面通过一张图来简要说明使用 ServerSocket 创建 TCP 服务器端和使用Sock创建客户端通信的流程:

这只是实现了单个服务端与客户端的通讯,要想实现与多个客户端的通讯,要在服务端的发送信息线程里把信息转发给各个客户端,在服务端里循环监听客户端的连接,每当有一个客户端连接则把该客户端放进一个集合里面(转发信息时用),然后为该客户端新建一个接收线程和一个发送线程。

具体实现代码:

Server端

package project20150806;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Scanner;

//发送信息线程
class SendThreat implements Runnable {
Socket socket;
//在这里使用PrintWriter流来向客户端发送信息,也可以用其它流
PrintWriter pWriter;
//接收来自主线程的客户端集合
private ArrayList<Socket> socketList;

//从键盘输入获取信息
Scanner scanner = new Scanner(System.in);

public SendThreat(Socket socket,ArrayList<Socket> socketList) {
super();
this.socket = socket;
this.socketList=socketList;
try {
//接收socket的字节输出流,用OutputStreamWriter把字节输出流转化为字符流,再传给PrintWriter
pWriter = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

@Override
public void run() {

while (true) {
//获取从键盘输入的信息
String strMsg =socket.getInetAddress().getHostAddress()+":"+ scanner.nextLine();
if (strMsg == "b") {
break;
}

//把服务器收到的信息转发给各个客户端
for (Socket clientSock : socketList) {
PrintWriter pWriter;
try {
//获取socket的输出流,用来向客户端发送信息
pWriter = new PrintWriter(clientSock.getOutputStream());
//输出信息给客户端
pWriter.println(strMsg);
//刷新输出流
pWriter.flush();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

// pWriter.close();
}
//			pWriter.println(strMsg);
//			pWriter.flush();
//			pWriter.close();
// System.out.println(strMsg);
}

}
}

//接收信息线程
class ReceiveThreat implements Runnable {
Socket socket;
BufferedReader bReader;
private ArrayList<Socket> socketList;

public ReceiveThreat(Socket socket, ArrayList<Socket> socketList) {
super();
this.socket = socket;
this.socketList = socketList;
try {
//获取socket的输入流
bReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));

} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

@Override
public void run() {
while (true) {

try {
String strMsg = bReader.readLine();
System.out.println(strMsg);

for (Socket clientSock : socketList) {
PrintWriter pWriter = new PrintWriter(clientSock.getOutputStream());
pWriter.println(strMsg);
pWriter.flush();
// pWriter.close();
}

} catch (IOException e) {
// TODO Auto-generated catch block
ChatServer.socketList.remove(socket);
}
}
}
}

public class ChatServer {

//定义一个集合用来存放 监听到的客户端socket
public static ArrayList<Socket> socketList = new ArrayList<>();

public static void main(String[] args) {
// TODO Auto-generated method stub
ServerSocket serverSocket = null;

try {
//新建一个服务端ServerSocket,锁定端口号为30000,端口号建议锁定大一点的
serverSocket = new ServerSocket(30000);
System.out.println("等待客户端连接...");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
while (true) {
Socket socket = null;
while (true) {
try {
//监听客户端的连接
socket = serverSocket.accept();
//加入集合
socketList.add(socket);
System.out.println("客户端 " + socket.getInetAddress().getHostAddress() + "连接成功!");

// showHello(socket);
//为该客户端分别开启一个发送信息线程和接收信息线程
new Thread(new SendThreat(socket,socketList)).start();
new Thread(new ReceiveThreat(socket, socketList)).start();

} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}

}


客户端:

package project20150806;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;

//发送信息线程
class SendClientThreat implements Runnable {
Socket socket;
PrintWriter pWriter;
Scanner scanner;

public SendClientThreat(Socket socket) {
super();
this.socket = socket;
this.scanner = new Scanner(System.in);
try {
pWriter = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

@Override
public void run() {

while (true) {
String strMsg =socket.getInetAddress().getHostAddress()+":"+ scanner.nextLine();
pWriter.println(strMsg);
pWriter.flush();

// System.out.println(strMsg);
}

}
}

//接收信息线程
class ReceiveClientThreat implements Runnable {
Socket socket;
BufferedReader bReader;

public ReceiveClientThreat(Socket socket) {
super();
this.socket = socket;
try {
bReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

@Override
public void run() {
try {

while (true) {
String strMsg = bReader.readLine();
System.out.println(strMsg);
}

} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

}
}

public class ChatClient {

private static Socket socket;

public static void main(String[] args) {
//服务端的IP
String IPAdress="192.168.1.199";
//创建一个客户端socket,指定服务端的IP和端口号
try {
socket = new Socket(IPAdress, 30000);
System.out.println("连接主机成功! ");

new Thread(new ReceiveClientThreat(socket)).start();
new Thread(new SendClientThreat(socket)).start();

} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

}

}


这样就可以实现简单的聊天室功能了。把从键盘获取的信息换成从文件获取的流,还可以实现文件传输功能。
如有不足之处请多多指教,谢谢!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息