c++ socket 服务器 线程池 海量 并发 windoes linux 源代码 SPServer

来源:互联网 发布:c语言如何生成exe文件 编辑:程序博客网 时间:2024/06/07 19:13
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 = 0< 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(10013);
        
// 初始化线程池
        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;
}
暂时就这些吧,希望对学习这一块的朋友有所帮助。
0 0
原创粉丝点击