socket服务端、开源网络库和线程池

java版本的socket服务端

public class Main {
    private static ServerSocket serverSocket;
    private final static ExecutorService exec = Executors.newFixedThreadPool(30);
    public static void main(String[] args) {
        try {
            serverSocket = new ServerSocket(8888);
            while (true) {
                Socket socket = serverSocket.accept();
                exec.execute(new ServerRunnable(socket));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

class ServerRunnable implements Runnable {
    private Socket socket;
    private InputStream is;
    private OutputStream out;
    private String reqStr;
    private String resContent;
    public ServerRunnable(Socket socket) {
        this.socket = socket;
    }
    @Override
    public void run() {
        handleSocket(socket);
    }
    private void handleSocket(Socket socket) {
        try {
            byte[] buffer = new byte[1024];
            is = socket.getInputStream();
            System.out.println(is);
            out = socket.getOutputStream();
            int len = 0;
            StringBuilder sb = new StringBuilder();
            while ((len = is.read(buffer)) != -1) {
                String str = new String(buffer, 0, len);
                sb.append(str);
            }
            reqStr = sb.toString();
            System.out.println(reqStr);
            resContent = "Welcome!";
            StringBuilder resBuilder  = new StringBuilder();
            resBuilder.append("HTTP/1.1 200 OK").append("\r\n").
            append("Date:").append(new Date()).append("\r\n").
            append("Content-Type:").append("text/plain;charset=UTF-8").append("\r\n").
            append("Content-Length:").append(resContent.getBytes().length).append("\r\n").
            append("\r\n");
            resBuilder.append(resContent);
            out.write(resBuilder.toString().getBytes());
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

C语言版的socket服务端

#include 
#include  
#include 
#include 

int main( int argc, char *argv[] )
{
    int sockfd, newsockfd, portno, clilen;
    char buffer[256];
    struct sockaddr_in serv_addr, cli_addr;
    int  n;

    /* First call to socket() function */
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) 
    {
        perror("ERROR opening socket");
        exit(1);
    }
    /* Initialize socket structure */
    bzero((char *) &serv_addr, sizeof(serv_addr));
    portno = 5001;
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = INADDR_ANY;
    serv_addr.sin_port = htons(portno);
 
    /* Now bind the host address using bind() call.*/
    if (bind(sockfd, (struct sockaddr *) &serv_addr,
                          sizeof(serv_addr)) < 0)
    {
         perror("ERROR on binding");
         exit(1);
    }
    /* Now start listening for the clients, here 
     * process will go in sleep mode and will wait 
     * for the incoming connection
     */
    listen(sockfd,5);
    clilen = sizeof(cli_addr);
    while (1) 
    {
        newsockfd = accept(sockfd, 
                (struct sockaddr *) &cli_addr, &clilen);
        if (newsockfd < 0)
        {
            perror("ERROR on accept");
            exit(1);
        }
        /* Create child process */
        pid = fork();
        if (pid < 0)
        {
            perror("ERROR on fork");
	    exit(1);
        }
        if (pid == 0)  
        {
            /* This is the client process */
            close(sockfd);
            doprocessing(newsockfd);
            exit(0);
        }
        else
        {
            close(newsockfd);//shutdown(newsockfd);或许会更好
        }
    } /* end of while */
}

void doprocessing (int sock)
{
        int n;
        char buffer[256];
       //bzero(buffer,256);

	 while(1){
	 
         printf("waiting for request...\n");
         //Reset data.
         memset(data_recv,0,256);
 
         i_recvBytes = read(sock,buffer,255);
         if(i_recvBytes == 0){
             printf("Maybe the client has closed\n");
             break;
         }
         if(i_recvBytes == -1){
             fprintf(stderr,"read error!\n");
             break;
         }
         if(strcmp(data_recv,"quit")==0){
             printf("Quit command!\n");
             break;                           //Break the while loop.
         }
         printf("read from client : %s\n",data_recv);
         if(write(fd,data_send,strlen(data_send)) == -1){
             break;
         }
     }

}

参考1:http://m.blog.csdn.net/blog/onlyonename/7080955
参考2:http://blog.csdn.net/yutianzuijin/article/details/24807417

注意:

1.accept是阻塞函数,会阻塞当前的进程直到有连接到来为止,一旦有客户端的连接accept就返回一个连接socket,即newsockfd,之后处理连接的进程会读取此newsockfd,获取客户端的数据。
2.服务端为了支持多个客户端的访问连接,需要将accept放在一个循环中,每当accept返回一个连接socket后就继续等待下一个客户端的访问。
3.tcp数据包在网络传输的过程中存在分割数据包的情况,即一个数据包分多次发送,因此在doprocessing函数内的read函数需要在一个while循环读里面。
4.fork出多进程来,返回值如果为0则为子进程,返回值为如果不是0,则是父进程,并且此返回值是子进程的PID。子进程和父进程只共享代码段,以及父进程的所有打开的文件描述符(慎用),不共享数据段、栈和堆,因此,在子进程中要关闭监听socket,在父进程中要关闭连接socket。
作为与fork的一个区别, POSIX通过pthread_create()函数创建线程,API定义如下:
int   pthread_create(pthread_t   *thread, pthread_attr_t *attr, void *(*start_routine)(void *), void *arg)
与fork()调用创建一个进程的方法不同,pthread_create()创建的线程并不具备与主线程(即调用pthread_create()的线 程)同样的执行序列,而是使其运行start_routine(arg)函数。thread返回创建的线程ID,而attr是创建线程时设置的线程属性 (见下)。pthread_create()的返回值表示线程创建是否成功。尽管arg是void *类型的变量,但它同样可以作为任意类型的参数传给start_routine()函数;同时,start_routine()可以返回一个void *类型的返回值,而这个返回值也可以是其他类型,并由pthread_join()获取。
5.跟大家分享几个C语言的开源网络库:spserver(c++), libevent(c语言), libev(c语言),libuv(c语言),ace(c++)简单调用这几个库的API即可实现可用于生产环境上的socket服务器,作为服务器性能压力测试的一款开源软件是jmeter,其方便好用性堪比loadrunner。现有版本的jmeter暂不支持对socket的压力测试,需要额外开发扩展插件,方法如下:http://www.cnblogs.com/linglingyuese/p/linglingyuese_sex.html或http://blog.csdn.net/a574258039/article/details/19549407

6.在多线程编程中,如果有一个子线程出现了段错误,那么整个进程都会挂掉,因此,要想稳定运行多线程,最好使用线程池的思想,即初始化时创建固定数目的足够用的线程,主循环中轮流使用这些线程,程序结束时退出所有线程,如果在主循环中动态创建、销毁线程,很难维持稳定的7x24小时服务。C语言版的多线程可参考:简单Linux C线程池 和 C语言实现简单线程池。

7.跟大家分享几个http的client库,在Java里面主要使用httpclient,在C/C++里面类似的库有:

  • curl - too heavyweight
  • poco - too heavyweight
  • neon - GPL
  • qlibc - relies on POSIX libraries
  • cpp-netlib - relies on Boost libraries
  • serf- relies on the Apache Portable Runtime library
  • urdl - relies on Boost libraries
  • HTTP Client C API - promising but requires a C++ wrapper
  • HttpClient - HTTPClient on mbed
  • Simple HTTP client in C   

关于以上几个开源库,可参考:

http://stackoverflow.com/questions/23842394/c-c-http-client-library-for-embedded-projects


你可能感兴趣的:(网络编程)