Java 网络编程
2013-09-16 15:03
337 查看
1、服务器多线程处理机制
为了确保一个服务器能为多个客户端服务,这里引入了多线程机制。Java处理多线程的方式非常直接,所以让服务器处理多线程并不是很难的事情。最基本的方法是在服务端(程序)里创建单个ServerSocket,并调用accept()方法来等候一个新的连接,一旦accept()方法返回结果,我们就取得获取结果是Socket,并用他新建一个线程,然后为那个特定的客户服务,然后再掉用accept()方法,等待下一个连接请求。
服务端代码:
package com.zkteco.server;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
class ServeOneJabber extends Thread {
private Socket socket;
private BufferedReader in;
private PrintWriter out;
public ServeOneJabber(Socket s) throws IOException {
socket = s;
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
// Enable auto-flush:
out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(
socket.getOutputStream())), true);
// If any of the above calls throw an
// exception, the caller is responsible for
// closing the socket. Otherwise the thread
// will close it.
start(); // Calls run()
}
public void run() {
try {
while (true) {
String str = in.readLine();
if (str.equals("END"))
break;
System.out.println("Echoing: " + str);
out.println(str);
}
System.out.println("closing...");
} catch (IOException e) {
} finally {
try {
socket.close();
} catch (IOException e) {
}
}
}
}
package com.zkteco.server;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class MultiJabberServer {
static final int PORT = 8080;
public static void main(String[] args) throws IOException {
ServerSocket s = new ServerSocket(PORT);
System.out.println("Server Started");
try {
while (true) {
// Blocks until a connection occurs:
Socket socket = s.accept();
try {
new ServeOneJabber(socket);
} catch (IOException e) {
// If it fails, close the socket,
// otherwise the thread will close it:
socket.close();
}
}
} finally {
s.close();
}
}
}
每次有新客户请求建立一个连接时,ServeOneJabber线程都会取得由accept()在main()中生成的Socket对
象。然后和往常一样,它创建一个BufferedReader,并用Socket自动刷新PrintWriter对象。最后,它调
用Thread的特殊方法start(),令其进行线程的初始化,然后调用run()。这里采取的操作与前例是一样
的:从套扫字读入某些东西,然后把它原样反馈回去,直到遇到一个特殊的"END"结束标志为止。
同样地,套接字的清除必须进行谨慎的设计。就目前这种情况来说,套接字是在ServeOneJabber外部创建
的,所以清除工作可以“共享”。若ServeOneJabber构建器失败,那么只需向调用者“掷”出一个违例即
可,然后由调用者负责线程的清除。但假如构建器成功,那么必须由ServeOneJabber对象负责线程的清除,
这是在它的run()里进行的。
请注意MultiJabberServer有多么简单。和以前一样,我们创建一个ServerSocket,并调用accept()允许一
个新连接的建立。但这一次,accept()的返回值(一个套接字)将传递给用于ServeOneJabber的构建器,由
它创建一个新线程,并对那个连接进行控制。连接中断后,线程便可简单地消失。
如果ServerSocket创建失败,则再一次通过main()掷出违例。如果成功,则位于外层的try-finally代码
块可以担保正确的清除。位于内层的try-catch块只负责防范ServeOneJabber构建器的失败;若构建器成
功,则ServeOneJabber线程会将对应的套接字关掉。
客户端代码:
package com.zkteco.client;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
class JabberClientThread extends Thread {
public static final int PORT = 8080;
private Socket socket;
private BufferedReader in;
private PrintWriter out;
private static int counter = 0;
private int id = counter++;
private static int threadcount = 0;
public static int threadCount() {
return threadcount;
}
public JabberClientThread(InetAddress addr) {
System.out.println("Making client " + id);
threadcount++;
try {
socket =
new Socket(addr, PORT);
} catch(IOException e) {
// If the creation of the socket fails,
// nothing needs to be cleaned up.
}
try {
in =
new BufferedReader(
new InputStreamReader(
socket.getInputStream()));
// Enable auto-flush:
out =
new PrintWriter(
new BufferedWriter(
new OutputStreamWriter(
socket.getOutputStream())), true);
start();
} catch(IOException e) {
// The socket should be closed on any
// failures other than the socket
// constructor:
try {
socket.close();
} catch(IOException e2) {}
}
// Otherwise the socket will be closed by
// the run() method of the thread.
} public void run() {
try {
for (int i = 0; i < 25; i++) {
out.println("Client " + id + ": " + i);
String str = in.readLine();
System.out.println(str);
}
out.println("END");
} catch (IOException e) {
} finally {
// Always close it:
try {
socket.close();
} catch (IOException e) {
}
threadcount--; // Ending this thread
}
}
}
package com.zkteco.client;
import java.io.IOException;
import java.net.InetAddress;
public class MultiJabberClient {
static final int MAX_THREADS = 40;
public static void main(String[] args) throws IOException,
InterruptedException {
InetAddress addr = InetAddress.getByName(null);
while (true) {
if (JabberClientThread.threadCount() < MAX_THREADS)
new JabberClientThread(addr);
Thread.currentThread().sleep(100);
}
}
}
JabberClientThread构建器获取一个InetAddress,并用它打开一个套接字。大家可能已看出了这样的一个
套路:Socket肯定用于创建某种Reader以及/或者Writer(或者InputStream和/或OutputStream)对
象,这是运用Socket的唯一方式(当然,我们可考虑编写一、两个类,令其自动完成这些操作,避免大量重
复的代码编写工作)。同样地,start()执行线程的初始化,并调用run()。在这里,消息发送给服务器,而
来自服务器的信息则在屏幕上回显出来。然而,线程的“存在时间”是有限的,最终都会结束。注意在套接
字创建好以后,但在构建器完成之前,假若构建器失败,套接字会被清除。否则,为套接字调用close()的
责任便落到了run()方法的头上。
threadcount跟踪计算目前存在的JabberClientThread对象的数量。它将作为构建器的一部分增值,并在
run()退出时减值(run()退出意味着线程中止)。在MultiJabberClient.main()中,大家可以看到线程的数
量会得到检查。若数量太多,则多余的暂时不创建。方法随后进入“休眠”状态。这样一来,一旦部分线程
最后被中止,多作的那些线程就可以创建了。大家可试验一下逐渐增大MAX_THREADS,看看对于你使用的系
统来说,建立多少线程(连接)才会使您的系统资源降低到危险程度。
为了确保一个服务器能为多个客户端服务,这里引入了多线程机制。Java处理多线程的方式非常直接,所以让服务器处理多线程并不是很难的事情。最基本的方法是在服务端(程序)里创建单个ServerSocket,并调用accept()方法来等候一个新的连接,一旦accept()方法返回结果,我们就取得获取结果是Socket,并用他新建一个线程,然后为那个特定的客户服务,然后再掉用accept()方法,等待下一个连接请求。
服务端代码:
package com.zkteco.server;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
class ServeOneJabber extends Thread {
private Socket socket;
private BufferedReader in;
private PrintWriter out;
public ServeOneJabber(Socket s) throws IOException {
socket = s;
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
// Enable auto-flush:
out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(
socket.getOutputStream())), true);
// If any of the above calls throw an
// exception, the caller is responsible for
// closing the socket. Otherwise the thread
// will close it.
start(); // Calls run()
}
public void run() {
try {
while (true) {
String str = in.readLine();
if (str.equals("END"))
break;
System.out.println("Echoing: " + str);
out.println(str);
}
System.out.println("closing...");
} catch (IOException e) {
} finally {
try {
socket.close();
} catch (IOException e) {
}
}
}
}
package com.zkteco.server;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class MultiJabberServer {
static final int PORT = 8080;
public static void main(String[] args) throws IOException {
ServerSocket s = new ServerSocket(PORT);
System.out.println("Server Started");
try {
while (true) {
// Blocks until a connection occurs:
Socket socket = s.accept();
try {
new ServeOneJabber(socket);
} catch (IOException e) {
// If it fails, close the socket,
// otherwise the thread will close it:
socket.close();
}
}
} finally {
s.close();
}
}
}
每次有新客户请求建立一个连接时,ServeOneJabber线程都会取得由accept()在main()中生成的Socket对
象。然后和往常一样,它创建一个BufferedReader,并用Socket自动刷新PrintWriter对象。最后,它调
用Thread的特殊方法start(),令其进行线程的初始化,然后调用run()。这里采取的操作与前例是一样
的:从套扫字读入某些东西,然后把它原样反馈回去,直到遇到一个特殊的"END"结束标志为止。
同样地,套接字的清除必须进行谨慎的设计。就目前这种情况来说,套接字是在ServeOneJabber外部创建
的,所以清除工作可以“共享”。若ServeOneJabber构建器失败,那么只需向调用者“掷”出一个违例即
可,然后由调用者负责线程的清除。但假如构建器成功,那么必须由ServeOneJabber对象负责线程的清除,
这是在它的run()里进行的。
请注意MultiJabberServer有多么简单。和以前一样,我们创建一个ServerSocket,并调用accept()允许一
个新连接的建立。但这一次,accept()的返回值(一个套接字)将传递给用于ServeOneJabber的构建器,由
它创建一个新线程,并对那个连接进行控制。连接中断后,线程便可简单地消失。
如果ServerSocket创建失败,则再一次通过main()掷出违例。如果成功,则位于外层的try-finally代码
块可以担保正确的清除。位于内层的try-catch块只负责防范ServeOneJabber构建器的失败;若构建器成
功,则ServeOneJabber线程会将对应的套接字关掉。
客户端代码:
package com.zkteco.client;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
class JabberClientThread extends Thread {
public static final int PORT = 8080;
private Socket socket;
private BufferedReader in;
private PrintWriter out;
private static int counter = 0;
private int id = counter++;
private static int threadcount = 0;
public static int threadCount() {
return threadcount;
}
public JabberClientThread(InetAddress addr) {
System.out.println("Making client " + id);
threadcount++;
try {
socket =
new Socket(addr, PORT);
} catch(IOException e) {
// If the creation of the socket fails,
// nothing needs to be cleaned up.
}
try {
in =
new BufferedReader(
new InputStreamReader(
socket.getInputStream()));
// Enable auto-flush:
out =
new PrintWriter(
new BufferedWriter(
new OutputStreamWriter(
socket.getOutputStream())), true);
start();
} catch(IOException e) {
// The socket should be closed on any
// failures other than the socket
// constructor:
try {
socket.close();
} catch(IOException e2) {}
}
// Otherwise the socket will be closed by
// the run() method of the thread.
} public void run() {
try {
for (int i = 0; i < 25; i++) {
out.println("Client " + id + ": " + i);
String str = in.readLine();
System.out.println(str);
}
out.println("END");
} catch (IOException e) {
} finally {
// Always close it:
try {
socket.close();
} catch (IOException e) {
}
threadcount--; // Ending this thread
}
}
}
package com.zkteco.client;
import java.io.IOException;
import java.net.InetAddress;
public class MultiJabberClient {
static final int MAX_THREADS = 40;
public static void main(String[] args) throws IOException,
InterruptedException {
InetAddress addr = InetAddress.getByName(null);
while (true) {
if (JabberClientThread.threadCount() < MAX_THREADS)
new JabberClientThread(addr);
Thread.currentThread().sleep(100);
}
}
}
JabberClientThread构建器获取一个InetAddress,并用它打开一个套接字。大家可能已看出了这样的一个
套路:Socket肯定用于创建某种Reader以及/或者Writer(或者InputStream和/或OutputStream)对
象,这是运用Socket的唯一方式(当然,我们可考虑编写一、两个类,令其自动完成这些操作,避免大量重
复的代码编写工作)。同样地,start()执行线程的初始化,并调用run()。在这里,消息发送给服务器,而
来自服务器的信息则在屏幕上回显出来。然而,线程的“存在时间”是有限的,最终都会结束。注意在套接
字创建好以后,但在构建器完成之前,假若构建器失败,套接字会被清除。否则,为套接字调用close()的
责任便落到了run()方法的头上。
threadcount跟踪计算目前存在的JabberClientThread对象的数量。它将作为构建器的一部分增值,并在
run()退出时减值(run()退出意味着线程中止)。在MultiJabberClient.main()中,大家可以看到线程的数
量会得到检查。若数量太多,则多余的暂时不创建。方法随后进入“休眠”状态。这样一来,一旦部分线程
最后被中止,多作的那些线程就可以创建了。大家可试验一下逐渐增大MAX_THREADS,看看对于你使用的系
统来说,建立多少线程(连接)才会使您的系统资源降低到危险程度。
相关文章推荐
- Java 网络编程学习笔记(一)基本网络概念
- java 基础复习 网络编程
- java_网络编程学习笔记(二)
- 黑马程序员_JAVA笔记24——网络编程(练习)
- Java 网络编程学习笔记(三) InetAddress、NetWorkInterface、URL
- Java——网络编程——TCP
- Java基础进阶_day17_(网络编程)
- bug笔记 - Java --- 网络编程使用BufferedInputStream从缓冲区中读不到数据(浅析BufferedInputStram和BufferedOutputStream的工作机制)
- 33、Java入门—网络编程之UDP编程
- JAVA 网络编程小记
- [笔记]JAVA-网络编程
- Java 网络编程1--url 和urlconnection
- JAVA 网络编程(IP地址)
- java基础—网络编程———聊天窗口的建立
- 黑马程序员--08JAVA高级视频网络编程一些总结笔记
- JAVA基础再回首(二十八)——网络编程概述、IP地址、端口号、TCP和UDP协议、Socket、UDP传输、多线程UDP聊天
- Java的网络编程初识
- java_网络编程学习笔记(一)
- java 网络编程回顾(一)
- Java学习笔记--网络编程Socket