李炎朔 编程分析
来源:互联网 发布:通达oa办公软件 编辑:程序博客网 时间:2024/06/14 02:31
/* server.c */
#include
#include
#include
#include
#include "wrap.h"
#define MAXLINE 80 //宏定义
#define SERV_PORT 8000 //端口
int main(int argc, char **argv)
{
int i, maxi, maxfd, listenfd, connfd, sockfd;
int nready, client[FD_SETSIZE]; //nready存放有数据请求的连接的个数;FD_SETSIZE是tcp最大连接数,client [FD_SETSIZE] 存放有数据请求的客户端;
ssize_t n;
fd_set rset, allset;
char buf[MAXLINE];
char str[INET_ADDRSTRLEN];
socklen_t cliaddr_len;
struct sockaddr_in cliaddr, servaddr;
listenfd = Socket(AF_INET, SOCK_STREAM, 0); //socket()打开一个网络通讯端口,返回一个套接字描述符给listenfd;
bzero(&servaddr, sizeof(servaddr)); //结构体清零;
servaddr.sin_family = AF_INET; //设置地址类型为ipv4;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);//转换ip地址字节序,网络地址为INADDR_ANY,这个宏表示本地任意IP地址
servaddr.sin_port = htons(SERV_PORT);//转换端口的字节序。
Bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)); //将所监听的端口号与服务器的地址、端口绑定;
Listen(listenfd, 20); //listen()使服务器进入监听状态 最多可以同时监听20个端口;
maxfd = listenfd; /* initialize */ //将所监听的最大的套接字描述符赋给maxfd;
maxi = -1; /* index into client[] array */
for (i = 0; i < FD_SETSIZE; i++)
client[i] = -1; /* -1 indicates available entry */ //FD_SETSIZE的最大值为1024,for循环将client[i]的值设为-1,client[i]在下文中用来保存最小的套接字描述符,这样可以把建立数据请求的端口赋给最前面的client[i];
FD_ZERO(&allset); //清空allset套接字描述符集。
FD_SET(listenfd, &allset);//向allset中添加监听到的端口;
for ( ; ; ) { //for 用于循环接受有数据请求,要与服务器交互的client的端口;
rset = allset; /* structure assignment */ // 把allset的内容赋给rset;
nready = select(maxfd+1, &rset, NULL, NULL, NULL);//select用于监听多个阻塞的文件描述符,当这些被阻塞的端口有数据请求或要与服务器交互时,select就会返回请求客户端的个数给nready,若没有,则返回0,若select调用出错,则会返回一个负值。由于最后一个关于时间的参数值是null,所以select会一直阻塞等待着client的请求,直到有数据交互的客户端产生。maxfd+1表示集合中描述符的范围即所有描述符的最大值加1,rset则是在关注哪个客户端有数据可读了,就把客户端的套接字描述符添加在rset集合中。
if (nready < 0) //select调用出错时,会返回一个负数给nready。该语句判断select是否调用成功。
perr_exit("select error");
if (FD_ISSET(listenfd, &rset)) { /* new client connection */ //判断listenfd所接受到的客户端的请求是否在rset集合中,这是一个监听到的客户端与所监听客户端中有数据请求的客户端的一个比对,测试该数据请求的客户端是否在监听的队列中。
cliaddr_len = sizeof(cliaddr); //把cliaddr结构体的长度赋给cliaddr_len,作为缓冲区的长度。
connfd = Accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len);//接受客户端的连接请求,与客户端建立连接。
printf("received from %s at PORT %d\n",
inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)),
ntohs(cliaddr.sin_port)); //打印客户端的ip地址和端口号。
for (i = 0; i < FD_SETSIZE; i++) //for循环,i作为client的下标,表示放有数据请求的客户端的最小索引
if (client[i] < 0) {
client[i] = connfd; /* save descriptor */
break; //把有数据请求的客户端的套接字描述符放置到client[i]中最靠前的位置。
}
if (i == FD_SETSIZE) { //若i以达到最大值FD_SETSIZE,则表示有数据请求的客户端已达到FD_SETSIZE
fputs("too many clients\n", stderr);
exit(1);
}
FD_SET(connfd, &allset);//向allset套接字描述符集中添加与服务器建立连接并有数据请求的客户端端口;
if (connfd > maxfd)
maxfd = connfd; //若此时建立并有数据请求的客户端已大于原来的套接字描述符最大值则用connfd从置maxfd;
if (i > maxi) //把maxi赋值为当前最大的放置建立连接并有数据请求客户端描述符的索引,以在下面的for循环语句中作为处理客户端请求个数的上限;
maxi = i; /* max index in client[] array */
if (--nready == 0) //若--nready为0,则表示当前的套接字描述符集中只有listenfd这个监听的描述符,没有客户端的数据请求端口,则进行下一轮的select循环;
continue; /* no more readable descriptors */
}
for (i = 0; i <= maxi; i++) { //for循环处理有数据请求的客户端;
if ( (sockfd = client[i]) < 0) //把client[i]中存放的客户端的套接字描述符赋给sockfd。若小于0,表示这个client[i]中没有套接字描述符。
continue; //继续执行for循环,查找数据请求的客户端;
if (FD_ISSET(sockfd, &rset)) { //测试sockfd是否在rset这个描述符集中;
if ( (n = Read(sockfd, buf, MAXLINE)) == 0) { // 读入客户端的数据,若n等于0表示客户端已经关闭了连接;
/* connection closed by client */
Close(sockfd); //客户端关闭连接了,服务器也关闭与客户端相应的连接;
FD_CLR(sockfd, &allset); //清空与客户端连接的套接字描述符在allset集中;
client[i] = -1; //同时将放置这个客户端套接字的数组位置设为-1,用来存放下一次的客户端数据请求的描述符;
} else { //若n不为0,则处理客户端的数据请求;
int j;
for (j = 0; j < n; j++)
buf[j] = toupper(buf[j]); //把客户端发来的数据变为大写;
Write(sockfd, buf, n); //将数据发回客户端;
}
if (--nready == 0) //再次判断nready,若--nready为0,则表示当前的套接字描述符集中只有listenfd这个监听的描述符,没有客户端的数据请求端口,则进行下一轮的select循环;
break; /* no more readable descriptors */
}
}
}
}
流程:
#include
#include
#include
#include
#include "wrap.h"
#define MAXLINE 80 //宏定义
#define SERV_PORT 8000 //端口
int main(int argc, char **argv)
{
int i, maxi, maxfd, listenfd, connfd, sockfd;
int nready, client[FD_SETSIZE]; //nready存放有数据请求的连接的个数;FD_SETSIZE是tcp最大连接数,client [FD_SETSIZE] 存放有数据请求的客户端;
ssize_t n;
fd_set rset, allset;
char buf[MAXLINE];
char str[INET_ADDRSTRLEN];
socklen_t cliaddr_len;
struct sockaddr_in cliaddr, servaddr;
listenfd = Socket(AF_INET, SOCK_STREAM, 0); //socket()打开一个网络通讯端口,返回一个套接字描述符给listenfd;
bzero(&servaddr, sizeof(servaddr)); //结构体清零;
servaddr.sin_family = AF_INET; //设置地址类型为ipv4;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);//转换ip地址字节序,网络地址为INADDR_ANY,这个宏表示本地任意IP地址
servaddr.sin_port = htons(SERV_PORT);//转换端口的字节序。
Bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)); //将所监听的端口号与服务器的地址、端口绑定;
Listen(listenfd, 20); //listen()使服务器进入监听状态 最多可以同时监听20个端口;
maxfd = listenfd; /* initialize */ //将所监听的最大的套接字描述符赋给maxfd;
maxi = -1; /* index into client[] array */
for (i = 0; i < FD_SETSIZE; i++)
client[i] = -1; /* -1 indicates available entry */ //FD_SETSIZE的最大值为1024,for循环将client[i]的值设为-1,client[i]在下文中用来保存最小的套接字描述符,这样可以把建立数据请求的端口赋给最前面的client[i];
FD_ZERO(&allset); //清空allset套接字描述符集。
FD_SET(listenfd, &allset);//向allset中添加监听到的端口;
for ( ; ; ) { //for 用于循环接受有数据请求,要与服务器交互的client的端口;
rset = allset; /* structure assignment */ // 把allset的内容赋给rset;
nready = select(maxfd+1, &rset, NULL, NULL, NULL);//select用于监听多个阻塞的文件描述符,当这些被阻塞的端口有数据请求或要与服务器交互时,select就会返回请求客户端的个数给nready,若没有,则返回0,若select调用出错,则会返回一个负值。由于最后一个关于时间的参数值是null,所以select会一直阻塞等待着client的请求,直到有数据交互的客户端产生。maxfd+1表示集合中描述符的范围即所有描述符的最大值加1,rset则是在关注哪个客户端有数据可读了,就把客户端的套接字描述符添加在rset集合中。
if (nready < 0) //select调用出错时,会返回一个负数给nready。该语句判断select是否调用成功。
perr_exit("select error");
if (FD_ISSET(listenfd, &rset)) { /* new client connection */ //判断listenfd所接受到的客户端的请求是否在rset集合中,这是一个监听到的客户端与所监听客户端中有数据请求的客户端的一个比对,测试该数据请求的客户端是否在监听的队列中。
cliaddr_len = sizeof(cliaddr); //把cliaddr结构体的长度赋给cliaddr_len,作为缓冲区的长度。
connfd = Accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len);//接受客户端的连接请求,与客户端建立连接。
printf("received from %s at PORT %d\n",
inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)),
ntohs(cliaddr.sin_port)); //打印客户端的ip地址和端口号。
for (i = 0; i < FD_SETSIZE; i++) //for循环,i作为client的下标,表示放有数据请求的客户端的最小索引
if (client[i] < 0) {
client[i] = connfd; /* save descriptor */
break; //把有数据请求的客户端的套接字描述符放置到client[i]中最靠前的位置。
}
if (i == FD_SETSIZE) { //若i以达到最大值FD_SETSIZE,则表示有数据请求的客户端已达到FD_SETSIZE
fputs("too many clients\n", stderr);
exit(1);
}
FD_SET(connfd, &allset);//向allset套接字描述符集中添加与服务器建立连接并有数据请求的客户端端口;
if (connfd > maxfd)
maxfd = connfd; //若此时建立并有数据请求的客户端已大于原来的套接字描述符最大值则用connfd从置maxfd;
if (i > maxi) //把maxi赋值为当前最大的放置建立连接并有数据请求客户端描述符的索引,以在下面的for循环语句中作为处理客户端请求个数的上限;
maxi = i; /* max index in client[] array */
if (--nready == 0) //若--nready为0,则表示当前的套接字描述符集中只有listenfd这个监听的描述符,没有客户端的数据请求端口,则进行下一轮的select循环;
continue; /* no more readable descriptors */
}
for (i = 0; i <= maxi; i++) { //for循环处理有数据请求的客户端;
if ( (sockfd = client[i]) < 0) //把client[i]中存放的客户端的套接字描述符赋给sockfd。若小于0,表示这个client[i]中没有套接字描述符。
continue; //继续执行for循环,查找数据请求的客户端;
if (FD_ISSET(sockfd, &rset)) { //测试sockfd是否在rset这个描述符集中;
if ( (n = Read(sockfd, buf, MAXLINE)) == 0) { // 读入客户端的数据,若n等于0表示客户端已经关闭了连接;
/* connection closed by client */
Close(sockfd); //客户端关闭连接了,服务器也关闭与客户端相应的连接;
FD_CLR(sockfd, &allset); //清空与客户端连接的套接字描述符在allset集中;
client[i] = -1; //同时将放置这个客户端套接字的数组位置设为-1,用来存放下一次的客户端数据请求的描述符;
} else { //若n不为0,则处理客户端的数据请求;
int j;
for (j = 0; j < n; j++)
buf[j] = toupper(buf[j]); //把客户端发来的数据变为大写;
Write(sockfd, buf, n); //将数据发回客户端;
}
if (--nready == 0) //再次判断nready,若--nready为0,则表示当前的套接字描述符集中只有listenfd这个监听的描述符,没有客户端的数据请求端口,则进行下一轮的select循环;
break; /* no more readable descriptors */
}
}
}
}
流程:
0
上一篇:ser and client.c 王晓峰
下一篇:嵌入式系统移植三步曲 赵晓晓
相关热门文章
- SHTML是什么_SSI有什么用...
- shell中字符串操作
- 卡尔曼滤波的原理说明...
- 关于java中的“错误:找不到或...
- shell中的特殊字符
- linux dhcp peizhi roc
- 关于Unix文件的软链接
- 求教这个命令什么意思,我是新...
- sed -e "/grep/d" 是什么意思...
- 谁能够帮我解决LINUX 2.6 10...
给主人留下些什么吧!~~
评论热议
0 0
- 李炎朔 编程分析
- VC数据库编程分析
- Linux串口编程分析
- VC数据库编程分析
- socket编程模型分析
- socket编程模型分析
- 面向对象编程分析
- Linux串口编程分析
- ALSA编程细节分析
- 输入法 编程分析
- ALSA编程细节分析
- ALSA编程细节分析
- ALSA编程细节分析
- S3C2440看门狗编程分析
- js编程性能分析
- ALSA编程细节分析
- ALSA编程细节分析
- javascript 性能分析:编程
- 解析 this.initialize.apply(this, arguments)
- Android 为应用程序创建桌面快捷方式
- ser and client.c 王晓峰
- 深入理解JVM(一)-Java运行时数据区域
- EXCEL中如何保持图片大小不随单元格变化而变化
- 李炎朔 编程分析
- 嵌入式系统移植三步曲 赵晓晓
- 嵌入式系统移植三步曲 孟明明
- jquery mobile项目 的不同设备的字体大小问题?
- linux下navicat for mysql无法连接问题解决方法
- 基于MFC平台的对话框软件模型
- server-client 服务器-客户端 赵晓晓
- 【JSP】jsp导出excel长数字不以科学计数法显示
- server-client 服务器-客户端 段彦青
原创粉丝点击
热门IT博客
热门问题
老师的惩罚
人脸识别
我在镇武司摸鱼那些年
重生之率土为王
我在大康的咸鱼生活
盘龙之生命进化
天生仙种
凡人之先天五行
春回大明朝
姑娘不必设防,我是瞎子
椰子树游乐设备
椰子树 棕榈树
椰子树棕榈树
儿童椰子树
椰子树画法
椰子树什么样子
椰子树工艺品
椰子树树干
很像椰子树
椰子树衬衫
椰子树花卉
大椰子树
椰子树的样子
国王椰子树
雕刻椰子树
有一颗椰子树
椰子树手工制作
手工制作椰子树
椰子树儿童画
椰子树植物
什么的椰子树
椰子树颜色
椰子树的特征
小椰子树怎么养
椰子树叶子
椰子树的孩子
不长椰子的椰子树
椰子树生长在哪里
椰子树玩具
儿童画椰子树
椰子树资料
椰子树有多高
椰子树背景墙
儿童乐园椰子树
椰子树多高
椰子树 种子
椰子树卡通
手工椰子树
椰子树的种子
椰子树模型
椰子树图画