服务端详解:
服务端的主要功能就是无限监听一个端口号,对客户端发来的连接请求给予回应,然后开辟新线程处理客户端。界面做的比较简单就是显示在线的用户,分为商家和学生。
一.监听客户端的socket连接请求
<span style="font-family:KaiTi_GB2312;font-size:18px;">package mainjframe;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.Toolkit;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.LinkedList;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
public class MainWindow extends JFrame{
ServerSocket server;
JTable user_table;
JTable seller_table;
JScrollPane user_jscrollPane;
JScrollPane seller_jscrollPane;
DefaultTableModel user_model;
DefaultTableModel seller_model;
String []user_headers = {"序号","在线学生"};
String []seller_headers = {"序号","在线商家"};
Object [][]cellData=null;
LinkedList<User> student,seller;
LinkedList<Socket> mysocket;
public static void main(String args[])
{
new MainWindow("服务端");
}
public MainWindow(String s)
{
super(s);
student = new LinkedList<User>();
seller = new LinkedList<User>();
mysocket = new LinkedList<Socket>();
addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent e)
{
dispose();
System.exit(0);
}
}
);
//获取屏幕大小
Dimension screenSize =Toolkit.getDefaultToolkit().getScreenSize();
//设置窗体的位置和大小
setBounds((screenSize.width-320)/2,(screenSize.height-240)/2,320,240);
setLayout(new GridLayout());
user_model = new DefaultTableModel(cellData,user_headers);
user_table = new JTable(user_model);
seller_model = new DefaultTableModel(cellData,seller_headers);
seller_table = new JTable(seller_model);
user_jscrollPane = new JScrollPane(user_table);
user_jscrollPane.setPreferredSize(new Dimension(160, 240));
seller_jscrollPane = new JScrollPane(seller_table);
seller_jscrollPane.setPreferredSize(new Dimension(160, 240));
add(user_jscrollPane);
add(seller_jscrollPane);
setVisible(true);
validate();
startServer();
}
void update()
{
user_model.setRowCount(0);
seller_model.setRowCount(0);
for(int i=0;i<student.size();i++)
{
user_model.addRow(new Object[]{i+1,student.get(i).account});
}
for(int i=0;i<seller.size();i++)
{
seller_model.addRow(new Object[]{i+1,seller.get(i).account});
}
}
void startServer() {
int i = 0;
try {
//设置监听端口号和最大接入数
server = new ServerSocket(8889, 3);
System.out.println("==========start===========快点来啊");
new Thread(new ListenThread(this)).start();
while (true) {
Socket socket = server.accept();
mysocket.add(socket);
i++;
System.out.println("第" + i + "个用户连接成功!");
System.out.println("该用户端的地址信息为:"+socket.getInetAddress());
new Thread(new ServerThread(socket,this)).start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
class ListenThread implements Runnable
{
private MainWindow mainWindow;
public ListenThread(MainWindow mainWindow)
{
this.mainWindow = mainWindow;
}
public void run()
{
while(true)
{
for(int i=0;i<mainWindow.mysocket.size();i++)
{
if(mainWindow.mysocket.get(i).isClosed())
{
for(int j=0;j<mainWindow.student.size();j++)
{
if(mainWindow.student.get(i).address == mainWindow.mysocket.get(i).getInetAddress())
mainWindow.student.remove(mainWindow.student.get(i));
}
for(int j=0;j<mainWindow.seller.size();j++)
{
if(mainWindow.seller.get(i).address == mainWindow.mysocket.get(i).getInetAddress())
mainWindow.seller.remove(mainWindow.seller.get(i));
}
mainWindow.update();
mainWindow.mysocket.remove(mainWindow.mysocket.get(i));
System.out.println("客户端已经断开");
}
}
try
{
Thread.sleep(500);
}
catch(Exception e)
{}
}}
}
</span>
在进程中使用while循环不断监听客户端发过来的请求,一旦请求建立成功就新建一个ServerThread子线程来处理客户端的请求,而主线程继续等待。同时开辟一个ListenThread线程不断判断哪一个线程已经断开连接。
二.在ServerThread中对客户端的请求进行处理
<span style="font-family:KaiTi_GB2312;font-size:18px;">package mainjframe;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
public class ServerThread implements Runnable {
private Socket socket;
private String accept;
String account,passwd;
DataInputStream in = null;
DataOutputStream out = null;
LinkMySql linkMySql;
String dept;
private MainWindow mainWindow;
// 创建静态全局变量
public ServerThread(Socket socket,MainWindow mainWindow)
{
this.mainWindow = mainWindow;
this.socket = socket;
linkMySql = new LinkMySql(this);
}
// 任务是为一个用户提供服务
@Override
public void run()
{
try
{
// 读取客户端传过来信息的DataInputStream
in = new DataInputStream(socket.getInputStream());
// 向客户端发送信息的DataOutputStream
out = new DataOutputStream(socket.getOutputStream());
System.out.println("放马过来吧!!!!");
// 读取来自客户端的信息
accept = in.readUTF();
System.out.println(accept);
}
catch (IOException e)
{
e.printStackTrace();
}
if(accept.equals("LOGIN"))
{
try
{
account = in.readUTF();
passwd = in.readUTF();
System.out.println("用户名:"+account+"\n密码:"+passwd);
for(int i=0;i<mainWindow.student.size();i++)
{
if(account.equals(mainWindow.student.get(i).account))
{
socket.close();
}
}
for(int i=0;i<mainWindow.seller.size();i++)
{
if(account.equals(mainWindow.seller.get(i).account))
{
socket.close();
}
}
dept = linkMySql.query(account,passwd);
out.writeUTF(dept);
if(dept.equals("student"))
{
User temp = new User();
temp.account = account;
temp.passwd = passwd;
temp.type = "student";
temp.address = socket.getInetAddress();
mainWindow.student.add(temp);
mainWindow.update();
linkMySql.initStudent(in,out);
linkMySql.handleOrder();
}
else if(dept.equals("seller"))
{
User temp = new User();
temp.account = account;
temp.passwd = passwd;
temp.type = "seller";
temp.address = socket.getInetAddress();
mainWindow.seller.add(temp);
mainWindow.update();
linkMySql.initseller(in,out);
}
}
catch(IOException e)
{
}
}
else if(accept.equals("REGISTER"))
{
}
}
} </span>
先读取客户端发来的请求,然后进入对应的功能模块,如果是用户登录,则进行sql语句操作并对结果做出反应,如果查询错误则关闭该线程,判断为学生则加入学生链表并初始化学生端的商品信息和店铺信息,判断为商家则把改商家的商品信息发过去并查找相应的订单表,把属于该商家的订单发给商家。
服务端的主要功能就是利用socket和多线程把学生端和商家端连接起来,并把所有对数据的操作集中在服务端来做,全部由服务端与数据库进行交互,保证数据的安全。