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.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();
}
}
}
这样就可以实现简单的聊天室功能了。把从键盘获取的信息换成从文件获取的流,还可以实现文件传输功能。
如有不足之处请多多指教,谢谢!
这只是实现了单个服务端与客户端的通讯,要想实现与多个客户端的通讯,要在服务端的发送信息线程里把信息转发给各个客户端,在服务端里循环监听客户端的连接,每当有一个客户端连接则把该客户端放进一个集合里面(转发信息时用),然后为该客户端新建一个接收线程和一个发送线程。
具体实现代码:
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();
}
}
}
这样就可以实现简单的聊天室功能了。把从键盘获取的信息换成从文件获取的流,还可以实现文件传输功能。
如有不足之处请多多指教,谢谢!
相关文章推荐
- java对世界各个时区(TimeZone)的通用转换处理方法(转载)
- java-注解annotation
- java-模拟tomcat服务器
- java-用HttpURLConnection发送Http请求.
- java-WEB中的监听器Lisener
- Linux socket 初步
- Android IPC进程间通讯机制
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- Python3写爬虫(四)多线程实现数据爬取
- 介绍一款信息管理系统的开源框架---jeecg
- 聚类算法之kmeans算法java版本
- java实现 PageRank算法
- PropertyChangeListener简单理解
- 插入排序
- 冒泡排序
- 堆排序