码迷,mamicode.com
首页 > 其他好文 > 详细

时间获取程序服务器 TCP 协议相关性

时间:2014-08-24 23:56:43      阅读:555      评论:0      收藏:0      [点我收藏+]

标签:style   blog   http   color   os   使用   io   for   ar   

本文为senlie原创,转载请保留此地址:http://blog.csdn.net/zhengsenlie


最初代码: 

这是一个简单的时间获取服务器程序。它和时间获取程序客户端一道工作。
 TCP/IPv4, IPv6 协议相关
 IPv4 --> IPv6 (把代码中出现的左边的字符串换为右边的,就变成了IPv6版本的)
 sockaddr_in --> sockaddr_in6
 AF_INET --> AF_INET6
 sin_family --> sin6_family
 sin_port --> sin6_port
 sin_addr --> sin6_addr


#include "unp.h"
#include <time.h>


int
main(int argc, char **argv)
{
int listenfd, connfd;
struct sockaddr_in servaddr;
char buff[MAXLINE];
time_t ticks;


//1.创建 TCP 套接字  --> 为什么不检查一下创建成功还是失败呢 ? 
// --> 大写字母开头的函数,如 Socket 是包裹函数,里面已经进行了错误处理
listenfd = Socket(AF_INET, SOCK_STREAM, 0);


//2.把服务器的众所周知的端口捆绑到套接字
//使用 bzero 把套接字地址结构 servaddr 清零
    //设置地址族为 AF_INET
//设置 IP 地址为 INADDR_ANY 。如果服务器主机骨多个网络接口,服务器进程就可以在任意网络接口上接受客户连接
    //设置端口号为 13
bzero(&servaddr, sizeof(servaddr));  
servaddr.sin_family      = AF_INET; 
servaddr.sin_addr.s_addr = htonl(INADDR_ANY); 
servaddr.sin_port        = htons(13);  
//绑定套接字
Bind(listenfd, (SA *) &servaddr, sizeof(servaddr));


//3.把套接字转换为监听套接字
//这样才可以接受来自客户的外来连接
//LISTENQ 指定最大客户连接数
Listen(listenfd, LISTENQ);


//4.接受客户连接,发送应答
for ( ; ; ) {
//服务器进程在 accept 调用中被挂起,等某个客户连接的到达,完成 TCP 三次握手后 accept 才返回
connfd = Accept(listenfd, (SA *) NULL, NULL); //已连接描述符


        ticks = time(NULL);
        snprintf(buff, sizeof(buff), "%.24s\r\n", ctime(&ticks));
        Write(connfd, buff, strlen(buff)); //把当前时间写给客户
        
//5.终止连接
// close 调用引发 TCP 连接终止序列。总共发送四个 TCP 分组。
// 每个方向一个 Fin,每个 Fin 又由各自的对端确认
Close(connfd);
}
}


问题1:协议相关
改善:使用 getaddrinfo 和 tcp_listen 来同时支持 IPv4 和 IPv6
/**
* TCP 协议无关,调用 getaddrinfo 和 tcp_listen
**/
#include "unp.h"


int
tcp_listen(const char *host, const char *serv, socklen_t *addrlenp)
{
int listenfd, n;
const int on = 1;
struct addrinfo hints, *res, *ressave;


//1.调用 getaddrinfo 
//协议地址话为 AF_UNSPEC ,套接字类型为 SOCK_STREAM
//因为本函数供服务器使用,所以还要加一个 AI_PASSIVE 的标志
bzero(&hints, sizeof(struct addrinfo));
hints.ai_flags = AI_PASSIVE;
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;


if ( (n = getaddrinfo(host, serv, &hints, &res)) != 0)
err_quit("tcp_listen error for %s, %s: %s",
host, serv, gai_strerror(n));
ressave = res;


//2.尝试每个 addrinfo 结构直到成功或到达链表尾
do {
//创建套接字
listenfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (listenfd < 0)
continue; /* error, try next one */


//设置套接字选项
Setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));

//绑定套接字
if (bind(listenfd, res->ai_addr, res->ai_addrlen) == 0)
break; //成功

//绑定失败,尝试下一个
Close(listenfd);
} while ( (res = res->ai_next) != NULL);


//3.检查是否失败
if (res == NULL) //socket() 或 bind() 得到的 errorno 
err_sys("tcp_listen error for %s, %s", host, serv);


//4.把套接字转换为监听套接字
Listen(listenfd, LISTENQ);


if (addrlenp)
*addrlenp = res->ai_addrlen; /* return size of protocol address */


//5.调用 freeaddrinfo 清理由 getaddrinfo 返回的动态存储空间
freeaddrinfo(ressave);


//6.返回建立的监听套接字
return(listenfd);
}
/* end tcp_listen */


int
Tcp_listen(const char *host, const char *serv, socklen_t *addrlenp)
{
return(tcp_listen(host, serv, addrlenp));
}


/**
* TCP 协议无关,调用 getaddrinfo 和 tcp_listen
**/
#include "unp.h"
#include <time.h>


int
main(int argc, char **argv)
{
int listenfd, connfd;
socklen_t len;
char buff[MAXLINE];
time_t ticks;
struct sockaddr_storage cliaddr;


//1.利用 Tcp_listen 得到监听套接字
if (argc == 2)
listenfd = Tcp_listen(NULL, argv[1], &addrlen);
else if (argc == 3)
listenfd = Tcp_listen(argv[1], argv[2], &addrlen);
else
err_quit("usage: daytimetcpsrv1 [ <host> ] <service or port>");



//2.服务器循环。接受客户连接,发送应答
for ( ; ; ) {
len = sizeof(cliaddr);
//服务器阻塞在 accept 调用,等待客户连接
connfd = Accept(listenfd, (SA *)&cliaddr, &len);
printf("connection from %s\n", Sock_ntop((SA *)&cliaddr, len));


//发送应答
ticks = time(NULL);
snprintf(buff, sizeof(buff), "%.24s\r\n", ctime(&ticks));
Write(connfd, buff, strlen(buff));

//关闭已连接套接字
Close(connfd);
}
}


问题2:一次只能处理一个客户
改善:大多数 UDP 服务器是迭代的,一次只处理一个客户。大多数 TCP 服务器是并发的。
并发最简单的技术是调用 fork 函数为每个客户创建一个子进程。其他技术包括使用线程
代替 fork,或在服务器启动时预先 fork 一定数量的子进程
这部分的内容在 回射服务器程序 里有相应的代码示例
问题3:长时间运行
改善: todo

时间获取程序服务器 TCP 协议相关性

标签:style   blog   http   color   os   使用   io   for   ar   

原文地址:http://blog.csdn.net/zhengsenlie/article/details/38802299

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!