Java Tcp Socket聊天系统模型(主要为了学习线程)

TcpSocekt通信模型


Tcp Socket是面向连接的,所以Server端的accept()方法,一直等着客户端的连接,如果连接成功,则两者进行通信,这种是同步的,因为accept()一直在那儿等着,时刻的等着,实际中的聊天系统是采用异步方式,当有请求的时候就调用accept()方法,没有请求的时候该做什么就做什么去,不需要在那儿等着,不浪费资源,一种异步的方式。这个例子只是为了学习线程而准备的。
端口有TCP端口和UDP端口两种,端口号都是从0到65535,TCP端口在3层,UDP不是四层就是7层 TCP和UDP的协议也不相同,TCP比UDP安全,更多TCP和UDP区别上google,baidu。

[size=x-large][color=red]服务器端编码[/color][/size]

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.StringTokenizer;
import java.util.Vector;

/**
* 服务器端编码
* @author 欧阳平 2009-3-17
*/
public class ChatServer {
static int port = 5566;//端口号
static Vector<Client> clients = new Vector<Client>(10);//存储连接客户信息
static ServerSocket server = null; //建立服务器socket
static Socket socket = null; //套接字连接
/**
* Constructs
*/
public ChatServer() {
try {
System.out.println("Server start...");
server = new ServerSocket(port); //初始化服务器套接字
while (true) {
socket = server.accept(); //等待连接
System.out.println(socket.getInetAddress()+"连接\n");//得到客户机地址
Client client = new Client(socket); //实例化一个客户线程(其中线程Client中有Socket,这里的的Socket只是起个过度作用)
//
clients.add(client);//增加客户线程到向量中
client.start();//启动线程
notifyChatRoom(); //监视聊天室连接变化
}
} catch (Exception ex) {
ex.printStackTrace();//输出出错信息
}
}

public static void notifyChatRoom() { //监视客户端线程
StringBuffer newUser = new StringBuffer("newUser");
for (int i = 0; i < clients.size(); i++) {
Client c = (Client)clients.elementAt(i);
newUser.append(":"+c.name); //客户端姓名字符串
}
sendClients(newUser);//发送信息到客户端
}

public static void sendClients(StringBuffer message) {
for (int i= 0 ; i < clients.size(); i++) {
Client client = (Client)clients.elementAt(i);//分别得到每个客户端的连接
client.send(message);//发送信息
}
}

public void closeAll() { //关闭所有连接
while (clients.size() > 0 ) { //遍历整个Vector
Client client = (Client) clients.firstElement(); //得到一个客户端
try {
client.socket.close();
} catch(IOException ex) {
ex.printStackTrace(); // 输出错误信息
}
clients.removeElement(client); //移出客户端
}
}

public static void disconnect(Client c) {// 断开客户端
try {
System.err.println(c.ip+"断开连接\n");
} catch (Exception ex) {
ex.printStackTrace();
}
clients.removeElement(c);
c.socket = null;
}


/**
* main方法
* @param args
*/
public static void main(String[] args) {
new ChatServer();

}
class Client extends Thread {
Socket socket;//连接端口
String name ;//用户姓名
String ip; //客户端ip地址
BufferedReader reader;//输入流
PrintStream ps;//输出流
public Client(Socket s) {
socket = s;
try {
reader = new BufferedReader(new InputStreamReader(s.getInputStream()));//得到输入流
ps = new PrintStream(s.getOutputStream());//得到输出流
String info = reader.readLine();//读取接收到的信息
StringTokenizer stinfo = new StringTokenizer(info,":"); //分解字符串
String head = stinfo.nextToken(); //获取关键字
System.out.println(stinfo.toString());
System.out.println(head);
if (stinfo.hasMoreTokens()){
name = stinfo.nextToken() ;//获取用户名
}
if (stinfo.hasMoreTokens()) {
ip = stinfo.nextToken(); //获取IP地址
}
} catch (IOException ex) {
ex.printStackTrace();
}
System.out.println(name);
System.out.println(ip);
}

public void send (StringBuffer msg) {
ps.println(msg); //输出信息
ps.flush();
}
public void run() {
while (true) {
String line = null;
try {

line = reader.readLine();
System.out.println("line:"+line);

} catch (IOException ex) {
ex.printStackTrace(); //输出错误信息
ChatServer.disconnect(this);//断开连接
ChatServer.notifyChatRoom();//更新信息
return ;
}
if (line == null) { //客户离开
ChatServer.disconnect(this);
ChatServer.notifyChatRoom();
return ;
}
StringTokenizer st = new StringTokenizer(line,":");//分解字符串
String keyword = st.nextToken();
if (keyword.equals("MSG")) { //发送来的聊天信息
StringBuffer msg = new StringBuffer("MSG:");
msg.append(name); //在信息上增加用户名
msg.append(st.nextToken("\0\n"));
ChatServer.sendClients(msg);//发送聊天语句到各个客户端
System.out.println(msg);
} else if (keyword.equals("quit")) { //退出命令
ChatServer.disconnect(this); //断开连接
ChatServer.notifyChatRoom(); //刷新信息
}
}
}
}

}




[color=red][size=x-large]//客户端编码[/size][/color]

import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Color;
import java.awt.Label;
import java.awt.TextArea;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.InetAddress;
import java.net.Socket;
import java.util.StringTokenizer;

import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;

/**
* 基于Socket网络聊天程序 客户端编码
* @author 欧阳平 2009-3-17
*/
public class ChatClient extends JFrame implements ActionListener,Runnable{

TextField tfName = new TextField(15);//姓名输入文本域
Button btConnect = new Button("连接");//连接按钮
Button btDisconnect = new Button("断开连接");//断开连接按钮
TextArea tfChat = new TextArea(8,27);//显示聊天信息文本域
Button btSend = new Button("发送");
TextField tfMessage = new TextField(30);//聊天输入
java.awt.List list1 = new java.awt.List(9);//显示在线用户信息
Socket socket = null;//连接端口
PrintStream ps = null;//输出流
Listen listen = null;
//监听线程类
class Listen extends Thread {
BufferedReader reader;
PrintStream ps;
String cname;
Socket socket;
ChatClient chatClient;
public Listen(ChatClient client,String name,Socket socket) {
try {
this.chatClient = client;
this.socket = socket;
this.cname = name;
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
ps = new PrintStream(socket.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
}
}
public void run() {
while (true) {
String line=null ;
try {
line = reader.readLine(); //读取数据流
System.out.println("客户端:"+line);

}catch (IOException ex) {
ex.printStackTrace();
ps.println("quit");; //断开连接
return;
}
StringTokenizer stinfo = new StringTokenizer(line,":"); //分解字符串
String keyword = stinfo.nextToken();
if (keyword.equals("MSG")) {
chatClient.tfChat.append(line+"\n");
}
else if (keyword.equals("newUser")){
chatClient.list1.clear();
chatClient.list1.add("users", 0);
int i = 1;
while (stinfo.hasMoreTokens()) {
chatClient.list1.add(stinfo.nextToken(), i++);
}
}
}

}
}
public void actionPerformed(ActionEvent e) {
try{
if(e.getSource()==btConnect) { //点击连接按钮
if (socket == null) {
socket = new Socket(InetAddress.getLocalHost(),5566);//实例化一个套接字
ps = new PrintStream(socket.getOutputStream());//获取输出流,写入信息
StringBuffer info = new StringBuffer("info:");
String userinfo = tfName.getText()+":"+InetAddress.getLocalHost().toString();
ps.println(info.append(userinfo));//输出信息
ps.flush();
listen = new Listen(this,tfName.getText(),socket);
listen.start();
}
} else if (e.getSource() == btDisconnect) { //点击断开连接按钮
disconnect();
} else if (e.getSource() == btSend) { //点击发送按钮
if (socket != null) {
StringBuffer msg = new StringBuffer("MSG:");
String msgtxt = new String(tfMessage.getText());
ps.println(msg.append(msgtxt));//发送信息
ps.flush();
} else {
JOptionPane.showMessageDialog(this, "请先连接!", "提示", 1);
}
}

} catch (Exception ex) {
ex.printStackTrace();//输出错误信息
}
}
public void disconnect() { //断开连接方法
if (socket != null) {
ps.println("quit");//发送信息
ps.flush();

socket = null;
tfName.setText("");
}
}








public ChatClient(Socket socket) {


this.setLayout(new BorderLayout());

JPanel panel1 = new JPanel();
Label label = new Label("姓名");
panel1.setBackground(Color.orange);
panel1.add(label);
panel1.add(tfName);
panel1.add(btConnect);
panel1.add(btDisconnect);
this.add(panel1,BorderLayout.NORTH);

JPanel panel2 = new JPanel();
panel2.add(tfChat);
panel2.add(list1);
this.add(panel2,BorderLayout.CENTER);

JPanel panel3 = new JPanel();
Label label2 = new Label("聊天信息");
panel3.add(label2);
panel3.add(tfMessage);
panel3.add(btSend);
this.add(panel3,BorderLayout.SOUTH);

this.setBounds(50,50,400,350);
this.setVisible(true);

btConnect.addActionListener(this);
btDisconnect.addActionListener(this);
btSend.addActionListener(this);

}

/**
* @param args
*/
public static void main(String[] args) {
ChatClient client = new ChatClient(new Socket());
System.out.println(client.socket);
}


[b][color=red][size=xx-large]在想做东西的时候,不能只拿着代码就想编程,先搞清楚原理规则,然后动手实践,否则事倍功半!了解规则,熟悉规则。[/size][/color][/b]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值