原来的网址: http://blog.sina.com.cn/s/blog_6294abe701011tyl.html
对socket服务器海量并发比较感兴趣,从网上搜了一些材料,和大家分享一下:
一、SPServer: 一个基于线程池(包括HAHS和LF)的开源服务器框架
SPServer 是一个实现了半同步/半异步(Half-Sync/Half-Async)和领导者/追随者(Leader/Follower) 模式的服务器框架,能够简化 TCP server 的开发工作。
SPServer 使用 c++ 实现,目前实现了以下功能:
1.封装了 TCP server 中接受连接的功能;
2.使用非阻塞型I/O和事件驱动模型,基于 libevent;
3.对于 HSHA 线程池,由主线程负责处理所有 TCP 连接上的数据读取和发送,因此连接数不受线程数的限制;主线程读取到的数据放入队列,由一个线程池处理实际的业务;
4.对于 LF 线程池,由线程池中的线程轮流获得 leader 角色进行处理;
5.一个 http 服务器框架,即嵌入式 web 服务器。
6.从 0.7 版本开始支持 ssl 。
项目主页
[url=http://code.google.com/p/spserver/]http://code.google.com/p/spserver/
下载地址
[url=http://freshmeat.net/redir/spserver/68862/url_tgz/spserver-0.3.src.tar.gz]http://spserver.googlecode.com/files/spserver-0.6.src.tar.gz
[url=http://code.google.com/p/spserver/downloads/list]http://code.google.com/p/spserver/downloads/list
详细的介绍
[url=http://iunknown.javaeye.com/blog/59804]http://iunknown.javaeye.com/blog/59804
HSHA 模式
[url=http://www.cs.wustl.edu/~schmidt/PDF/HS-HA.pdf]http://www.cs.wustl.edu/~schmidt/PDF/HS-HA.pdf
LF 模式
[url=http://www.cs.wustl.edu/~schmidt/PDF/lf.pdf]http://www.cs.wustl.edu/~schmidt/PDF/lf.pdf
关于 HSHA 和 LF 的一些介绍
[url=http://iunknown.javaeye.com/blog/60414]http://iunknown.javaeye.com/blog/60414
项目中包含一个线程池子项目
http://iunknown.javaeye.com/blog/38544
以上是从 http://www.chinaunix.net/jh/23/957813.html 中粘贴过来的,有兴趣可以看看这个链接。
二、http://www.pudn.com/downloads124/sourcecode/unix_linux/network/detail527666.html
这里有一个线程池+socket的服务器源代码,有兴趣的可以学习一下。
三、linux下最好的io模型是epoll,有点类似于windows下的完成端口,感觉select支持1000个左右就差不多了。要想支持10k以上的连接,需要考虑的问题有很多。
你可以看一下下面这个链接(C10k Problem)。
http://www.kegel.com/c10k.html
四、在网上无意看到一个多线程的Socket服务器端例子,觉得非常不错。特别是其中的线程池的思想,简单而且高效。虽然JDK1.5开始已经自带了线程池包,但该代码不失为学习Socket和多线程的一个好的入门例子。
下面的代码是对该例子的简单整理,补充了注释。
【代码一】PooledConnectionHandler:后台处理类
package
server;
import
java.io.BufferedReader;
import
java.io.FileNotFoundException;
import
java.io.FileReader;
import
java.io.IOException;
import
java.io.InputStreamReader;
import
java.io.PrintWriter;
import
java.net.Socket;
import
java.util.LinkedList;
import
java.util.List;
public
class
PooledConnectionHandler
implements
Runnable {
protected
Socket connection;
protected
static
List pool
=
new
LinkedList();
public
PooledConnectionHandler() {
}
public
void
run() {
while
(
true
) {
//
因为可能有多个线程同时去Pool中取Socket进行处理。
//
所以这里我们需同步,防止同一个请求被多次处理
synchronized
(pool) {
while
(pool.isEmpty()) {
try
{
pool.wait();
//
没有请求到来则等待
}
catch
(InterruptedException e) {
e.printStackTrace();
}
}
//
从池中取出一个Socket,准备进行处理
connection
=
(Socket) pool.remove(
0
);
}
//
取到Socket后则不需要同步了,因为此时是Connection是对象
//
级属性,在线程内部自己处理,不涉及公共资源的访问
handleConnection();
}
}
public
static
void
processRequest(Socket requestToHandle) {
//
因为有可能在向池中塞请求的时候,另外一个线程
//
正在从池中取Socket,所以这里需要同步一下
synchronized
(pool) {
//
将来自客户端的请求添加到请求队列末尾
pool.add(pool.size(), requestToHandle);
//
通知其它正在等待的线程有新请求来到,
//
此时所有处于wait状态的线程将被唤醒
pool.notifyAll();
}
}
public
void
handleConnection() {
try
{
PrintWriter streamWriter
=
new
PrintWriter(connection
.getOutputStream());
BufferedReader streamReader
=
new
BufferedReader(
new
InputStreamReader(connection.getInputStream()));
String fileToRead
=
streamReader.readLine();
BufferedReader fileReader
=
new
BufferedReader(
new
FileReader(
fileToRead));
String line
=
null
;
while
((line
=
fileReader.readLine())
!=
null
)
streamWriter.println(line);
fileReader.close();
streamWriter.close();
streamReader.close();
}
catch
(FileNotFoundException e) {
System.out.println(
""
);
}
catch
(IOException e) {
System.out.println(
""
+
e);
}
}
}
【代码二】PooledRemoteFileServer:多线程服务器端,负责创建线程池并等待客户端的连接请求
package
server;
import
java.io.IOException;
import
java.net.BindException;
import
java.net.ServerSocket;
import
java.net.Socket;
public
class
PooledRemoteFileServer {
protected
int
maxConnections;
protected
int
listenPort;
protected
ServerSocket serverSocket;
public
PooledRemoteFileServer(
int
aListenPort,
int
maxConnections) {
listenPort
=
aListenPort;
//
监听端口
this
.maxConnections
=
maxConnections;
//
最大同时连接
}
public
void
setUpHandlers() {
for
(
int
i
=
0
; i
<
maxConnections; i
++
) {
PooledConnectionHandler currentHandler
=
new
PooledConnectionHandler();
//
线程启动后将一直监控Socket队列,以轮询的方式
//
监控是否有新的客户端请求到来,如果有的话则取
//
出处理,无的话则继续等待直至请求到来
new
Thread(currentHandler,
"
Handler
"
+
i).start();
}
}
public
void
acceptConnections() {
try
{
ServerSocket server
=
new
ServerSocket(listenPort,
5
);
Socket incomingConnection
=
null
;
while
(
true
) {
incomingConnection
=
server.accept();
handleConnection(incomingConnection);
}
}
catch
(BindException be) {
System.out.println(
""
);
}
catch
(IOException ioe) {
System.out.println(
""
+
listenPort);
}
}
protected
void
handleConnection(Socket connectionToHandle) {
PooledConnectionHandler.processRequest(connectionToHandle);
}
public
static
void
main(String args[]) {
PooledRemoteFileServer server
=
new
PooledRemoteFileServer(
1001
,
3
);
//
初始化线程池
server.setUpHandlers();
//
开始在指定端口等待到来的请求
server.acceptConnections();
}
}
这个例子的精髓是在PooledConnectionHandler类,它首先创建一个公共的全局“线程池”(LinkList),然后启动线程监控线程池,与此同时服务器端在接收到客户端请求后将请求加到“线程池”中,这两个动作是异步的,在加的时候不允许读,在读得到时候不允许加(通过synchronized关键字控制),而且多个线程之间并不会互相影响,因为其中的connection属性是对象级的。
从这个例子中我们也可以学到在多线程的情况下,哪些变量是必须设置为全局的(static),哪些是必须设置为对象级的:即会被多个线程访问的资源必须设置为全局的,而跟线程处理状态,结果有关的属性一般必须设置为对象级的,以防止互相干扰。
其次就是在多线程情况下,哪些方法是可以设置为static的而不会出现线程安全的问题,哪些方法是不能设置为静态方法的:如果方法是属于控制流程,通知,派发的,那么一般可以设置为静态的。因为这些方法一般不需要多个,一个就够了。就如同控制器只要一个就够了。而业务逻辑实现方法一般不能设置为静态的,因为静态方法不能引用对象变量(非静态变量),但业务逻辑通常是需要针对不同的用户做出不同的处理的,所以几乎可以肯定的说是绝对会出现对象变量的。
五、
linux下多线程socket监听的c程序(例子)
#include<stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define PORT 8888
void *yourfunction(void *connect_fd)
{
int connfd = *((int *)connect_fd);
。。。。
} //在这里面直接对connfd调用read和write函数就可以和客户端收发数据了。
int main(void)
{
int sockfd, n, connfd;
pthread_t tid;
struct sockaddr_in servaddr;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1)
{
perror("socket:");
exit(1);
}
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(PORT);
n = bind(sockfd, (struct sockaddr *)&servaddr,sizeof(servaddr));
if (n == -1)
{
perror("bind:");
exit(1);
}
n = listen(sockfd, 20);
if (n == -1)
{
perror("listen:");
exit(1);
}
while (1)
{
connfd = accept(sockfd, (struct sockaddr*)&servaddr, NULL);
pthread_create(&tid, NULL,yourfunction, (void *)&connfd);
}
return 0;
}
暂时就这些吧,希望对学习这一块的朋友有所帮助。