socket网络编程客户服务器程序范式(一)

本节是关于linux网络编程各种模型的总的概述。

当开发一个linux服务器程序时,我们有如下若干方法可供选择:

        1.单进程迭代服务器:它的缺点是在当前客户被处理完之前,新到达的客户无法被服务
        2.单进程select服务器:进程内使用select同时服务多个客户
        3.多进程并发服务器:它为每个客户fork一个子进程来提供服务,这是传统服务器通常做法
        4.多线程并发服务器:它为每个客户创建一个线程来提供服务
        5.预先派生子进程:服务器启动后就派生一组子进程,形成一个子进程池,每来一个新客户,
           就从进程池内取一个可用进程来为它服务。
        6.预先创建线程:服务器启动后就创建一组线程,形成一个线程池。每个客户由池中的一个线程为其提供服务。

当开发一个linux客户程序时,有如下的设计方法可供选择
        1.停等模式客户程序:缺点,当它等待用户输入而阻塞时,无法监视网络事件,二是停等模式批处理效率极低
        2.改用select同时监视用户输入与网络事件,并用shutdown来正确的处理批量输入的问题
        3.改用非阻塞I/O客户程序
        4.创建子进程,父进程处理客户到服务器的数据,子进程处理服务器到客户的数据
        5.创建线程,主线程处理客户到服务器的数据,子线程处理服务器到客户的数据

下面若干节需要用到一些公共的读写函数,如下:

下面readline.c 文件提供了readline以及Readline函数,我们会用它来读取socket中的一行数据

/* include readline */
#include<stdio.h>
#include<unistd.h>
#include<errno.h>
#include<signal.h>
#define MAXLINE 4096
static int      read_cnt;
static char     *read_ptr;
static char     read_buf[MAXLINE];

static ssize_t
my_read(int fd, char *ptr)
{

        if (read_cnt <= 0) {
again:
                if ( (read_cnt = read(fd, read_buf, sizeof(read_buf))) < 0) {
                        if (errno == EINTR)
                                goto again;
                        return(-1);
                } else if (read_cnt == 0)
                        return(0);
                read_ptr = read_buf;
        }

        read_cnt--;
        *ptr = *read_ptr++;
        return(1);
}

ssize_t
readline(int fd, void *vptr, size_t maxlen)
{
        ssize_t n, rc;
        char    c, *ptr;

        ptr = vptr;
        for (n = 1; n < maxlen; n++) {
                if ( (rc = my_read(fd, &c)) == 1) {
                        *ptr++ = c;
                        if (c == '\n')
                                break;  /* newline is stored, like fgets() */
                } else if (rc == 0) {
                        *ptr = 0;
                        return(n - 1);  /* EOF, n - 1 bytes were read */
                } else
                        return(-1);             /* error, errno set by read() */
        }

        *ptr = 0;       /* null terminate like fgets() */
        return(n);
}

ssize_t
readlinebuf(void **vptrptr)
{
        if (read_cnt)
                *vptrptr = read_ptr;
        return(read_cnt);
}
/* end readline */

ssize_t
Readline(int fd, void *ptr, size_t maxlen)
{
        ssize_t         n;

        if ( (n = readline(fd, ptr, maxlen)) < 0)
        {
                perror("readline error");
                exit(1);
        }
        return(n);
}

下面的writen函数多次调用write实现了写n个字节到socket中

/*Write n bytes to fd*/
ssize_t writen(int fd, const void *vptr,size_t n)
{
        size_t nleft;
        ssize_t nwritten;
        const char *ptr;
        ptr = vptr;
        nleft = n;
        while(nleft > 0)
        {
                if((nwritten = write(fd,ptr,nleft)) < 0)
                {
                        if(errno == EINTR)
                        {
                                continue;
                        }else if(nleft == n)
                        {
                                return -1;
                        }else
                        {
                                break;
                        }
                }else if(nwritten == 0)
                {
                        break;
                }else
                {
                        nleft -= nwritten;
                        ptr += nwritten;
                }
        }
        return n-nleft;
}

下面是readn函数

ssize_t						/* Read "n" bytes from a descriptor. */
readn(int fd, void *vptr, size_t n)
{
	size_t	nleft;
	ssize_t	nread;
	char	*ptr;

	ptr = vptr;
	nleft = n;
	while (nleft > 0) {
		if ( (nread = read(fd, ptr, nleft)) < 0) {
			if (errno == EINTR)
				nread = 0;		/* and call read() again */
			else
				return(-1);
		} else if (nread == 0)
			break;				/* EOF */

		nleft -= nread;
		ptr   += nread;
	}
	return(n - nleft);		/* return >= 0 */
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值