一个简单的Socket例子其实可以看出很多问题,之前一直做这样的实验没有成功,今天又试了几遍,不断调试改进,对Socket大致有了一定的了解。
这个例子分为两个部分:服务端与客户端。
服务端用于启动一个进程,并且监听某一个端口,用accpe方法t进行阻塞,此时若accept接收到一个指向这个主机的这一个端口号,则accept运行并创建一个线程执行业务过程,线程一旦创建,进程又回到阻塞状态继续监听后续的请求。
客户端则用于发送指向某一个主机某一个端口号的请求。
服务端代码:
//Server.java
package com.llb.server;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class Server {
private static Connection conn = null;
public Server(){
System.out.println("Server is running !");
try {
Class.forName("com.mysql.jdbc.Driver");
try {
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/snjxc", "root", "root");
} catch (SQLException e) {
e.printStackTrace();
}
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
class ServerDemo extends Thread{
Socket socket;
InputStreamReader in;
PrintWriter out;
String username;
private Statement prestat = null;
private ResultSet rs = null;
public ServerDemo(Socket s){
this.socket = s;
}
@SuppressWarnings("unused")
@Override
public void run() {
System.out.println("Run now!");
char[] bytes = new char[64];
try{
in = new InputStreamReader(socket.getInputStream());
int len = 0;
StringBuffer sbr = new StringBuffer();
while((len = in.read(bytes))!= -1){
sbr.append(bytes);
if(sbr.toString().lastIndexOf("===END===")>0) break;
}
String str = sbr.toString();
if(null != str){
str = str.substring(str.lastIndexOf("===BEGIN===")+11, str.lastIndexOf("===END==="));
}
System.out.println(str);
if(null != str){
prestat = conn.createStatement();
rs = prestat.executeQuery("select * from tb_user");
if(rs.next()){
username = rs.getString("username");
}
}
out = new PrintWriter(socket.getOutputStream(),true);
out.print(Server.class.getSimpleName()+" : " + username);
out.flush();
}catch (Exception e){
e.printStackTrace();
}finally{
try {
in.close();
out.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
@SuppressWarnings("resource")
public static void main(String[] args){
ServerSocket ss;
Server server;
try {
ss = new ServerSocket(7501);
server = new Server();
while(true){
try{
Socket socket = ss.accept();
server.new ServerDemo(socket).start();
}catch(Exception ee){
ee.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
//程序的第56~59行,用了一个while以64字节为单位循环从输入流中读入并到bytes中。这样做的好处是可以让程序自主控制何时结束接收过程。
//注意:如若这个读入的过程不能结束,则整个线程将会处于持续的阻塞中不能往下执行。
//这也同时提醒了如果你的程序用readLine(),则你的请求字符串中一定要有断行标志,即\r\n结尾,不然后续代码是不会执行的。
很简单,服务端main方法里强制循环并用accept阻塞进程的自执行,若讲求到达,则创建一个线程,主进程继续阻塞。线程里主要定义了接收的方法,及业务流程,最后返回处理结果。
客户端代码:
//Client.java
package com.llb.client;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
public class Client {
public Client(){
Socket socket;
PrintWriter out;
InputStreamReader in ;
System.out.println("Starting....");
try{
socket = new Socket("127.0.0.1",7501);
out = new PrintWriter(socket.getOutputStream());
StringBuffer sbr = new StringBuffer("===BEGIN===");
//Append the message you want to send here
sbr.append("Client : Son of bitch , can you give me a reply ?");
sbr.append("===END===");
//Send the request
out.print(sbr.toString());
out.flush();
//Receive message from server
in = new InputStreamReader(socket.getInputStream());
StringBuffer response = new StringBuffer();
@SuppressWarnings("unused")
int len = 0;
char[] c = new char[1];
while((len = in.read(c)) != -1){
response.append(c);
}
String str = response.toString();
System.out.println(str);
}catch(Exception e){
e.printStackTrace();
}
}
public static void main(String[] args){
new Client();
}
}
socket = new Socket("127.0.0.1",7501);//创建请求的地址
运行结果:
Server开始运行,并在accept阻塞监听7501端口
启动Client端向服务器发送一个请求,服务器返回admin
服务器收到客户发来的请求并显示消息:
持续更新可参见我在GitHub的版本:https://github.com/Derrick-Li/Greeting/tree/master/socket