UNIX网络编程学习笔记(代码超详细解析)(持续更新)

1. 其他函数准备

1. TCP 回射服务器程序: str_echo 函数

#include “unp.h”void str_echo(int sockfd)
{ssize_t n;char    buf[MAXLINE];again:/*write()
函数定义:ssize_t write (int fd, const void * buf, size_t count); 
函数说明:write()会把参数buf所指的内存写入count个字节到参数fd所指的文件内。
返回值:如果顺利write()会返回实际写入的字节数(len)。当有错误发生时则返回-1,错误代码存入errno中。
*//*
read()函数定义:ssize_t read(int fd, void * buf, size_t count);函数说明:read()会把参数fd所指的文件传送count 个字节到buf 指针所指的内存中。返回值:返回值为实际读取到的字节数, 如果返回0, 表示已到达文件尾或是无可读取的数据。若参数count 为0, 则read()不会有作用并返回0。另外,以下情况返回值小于count:
*/while((n = read(sockfd, buf, MAXLINE)) > 0)Writen(sockfd, buf, n);if(n < 0 && errno == EINTR) // 被中断后继续执行goto again;else if(n < 0)err_sys("str_echo: read error");
}

2. TCP 回射客户端程序: str_cli 函数

#include "unp.h"void str_cli(FILE *fp, int sockfd)
{char    sendline[MAXLINE], recvline[MAXLINE];while(Fgets(sendline, NAXLINE, fp) != NULL){Writen(sockfd, sendline, strlen(sendline));if(Readline(sockfd, recvline, MALINE) == 0)err_quit("str_cli: server terminated prematurely");Fputs(recvline, stdout);}}

显示客户IP地址和端口号的时间获取服务器程序

#include	"unp.h"
#include	<time.h>#pragma clang diagnostic push
#pragma ide diagnostic ignored "EndlessLoop" //这是防止IDE输出警告的,不用管。
int
main(int argc, char **argv)
{int listenfd, connfd;// //len是一个 值——结果 变量socklen_t len;struct sockaddr_in servaddr,cliaddr;//cliaddr存放客户的协议地址//缓冲区存放转换结果char buff[MAXLINE];//存放时间time_t ticks;//初始化套接字,指定协议类型(第一个参数),套接字类型(字节流,数据报,或者原始套接字(极少使用))listenfd  = Socket(AF_INET,SOCK_STREAM,0);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));//使用socket创建的套接字最初为主动套接字,listen将其转换为一个被动套接字,指示内核应该接受指向该套接字的连接请求Listen(listenfd,LISTENQ);while (1){len =sizeof (cliaddr);//accept()函数功能是,从处于 established 状态的连接队列头部取出一个已经完成的连接,如果这个队列没有已经完成的连接,accept()函数就会阻塞,直到取出队列中已完成的用户连接为止。//如果accept成功,那么它的返回值是由内核生成的全新的描述符,代表与客户之间的 已成功建立 的TCP链接(已连接套接字描述符)//参数一:监听套接字描述符//参数二:客户进程的协议地址//参数三:该地址的大小//监听套接字与已连接套接字的区别:监听套接字在该服务的生命周期内一直存在,而每个已完成三次握手的TCP链接都会分配一个已连接套接字connfd = Accept(listenfd,(SA*) &cliaddr,&len);printf("connection from %s , port %d\n",inet_ntop(AF_INET,&cliaddr.sin_addr,buff,sizeof (buff)),//打印IP地址ntohs(cliaddr.sin_port));//打印端口号//获取时间ticks = time(NULL);//为什么不使用printf:因为printf的缓冲区不可控制,对我们来说难以控制snprintf(buff,sizeof (buff),"%.24s\r\n",ctime(&ticks));Write(connfd,buff,strlen(buff));Close(connfd);}}#pragma clang diagnostic pop

4.2作业

#include	"unp.h"int
main(int argc, char **argv)
{int					sockfd, n;char				recvline[MAXLINE + 1];struct sockaddr_in	servaddr;if (argc != 2)err_quit("usage: a.out <IPaddress>");if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)err_sys("socket error");bzero(&servaddr, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_port   = htons(13);	/* daytime server */if (inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0)err_quit("inet_pton error for %s", argv[1]);if (connect(sockfd, (SA *) &servaddr, sizeof(servaddr)) < 0)err_sys("connect error");struct sockaddr_in ss;char buff[MAXLINE];socklen_t  len;len =sizeof (ss);if (getsockname(sockfd,(SA*) &ss,&len) < 0) printf("错误喽!");else{printf("connection from %s,port %d\n",inet_ntop(AF_INET,&ss.sin_addr,buff,sizeof (buff)),ntohs(ss.sin_port));}while ( (n = read(sockfd, recvline, MAXLINE)) > 0) {recvline[n] = 0;	/* null terminate */if (fputs(recvline, stdout) == EOF)err_sys("fputs error");}if (n < 0)err_sys("read error");exit(0);
}

5.2

#include	"unp.h"#pragma clang diagnostic push
#pragma ide diagnostic ignored "EndlessLoop"
int
main(int argc, char **argv)
{int listenfd,confd;pid_t childpid;socklen_t clilen;struct sockaddr_in cliaddr,servaddr;listenfd =Socket(AF_INET,SOCK_STREAM,0);bzero(&servaddr,sizeof (servaddr));servaddr.sin_family = AF_INET;servaddr.sin_addr.s_addr =htonl(INADDR_ANY);servaddr.sin_port =htons(SERV_PORT);Bind(listenfd,(SA*) &servaddr,sizeof (servaddr));Listen(listenfd,LISTENQ);while (1){clilen =sizeof (cliaddr);confd = Accept(listenfd,(SA*) &cliaddr,&clilen);if((childpid = Fork()) == 0)//fork为每个客户派生一个处理它们的子进程//紫禁城关闭监听套接字,父进程关闭已连接套接字,紫禁城接着调用str_echo处理客户{Close(listenfd);str_echo(listenfd); exit(0);}Close(confd);}}
#pragma clang diagnostic pop

TCP回射客户程序

#include	"unp.h"#pragma clang diagnostic push
#pragma ide diagnostic ignored "EndlessLoop"
int main(int argc, char **argv)
{int sockfd;struct sockaddr_in servaddr;if (argc !=2 )err_quit("请输入IP地址。");sockfd = Socket(AF_INET,SOCK_STREAM,0);bzero(&servaddr,sizeof (servaddr));servaddr.sin_family = AF_INET;servaddr.sin_port = htons(SERV_PORT);Inet_pton(AF_INET,argv[1],&servaddr.sin_addr);//将IP地址转换为二进制机器可读Connect(sockfd,(SA*) &servaddr,sizeof (servaddr));str_cli(stdin,sockfd);//回射函数exit(0);
}
#pragma clang diagnostic pop

僵死进程:

   (1)概念:   进程实体已经释放,但进程对应的PCB进程控制块(进程描述符)还在.(2)产生的条件:  子进程比父进程结束的早,且父进程没有调用 wait() 获取子进程的退出码,这时子进程就变为僵死进程.(3)若子进程比父进程结束的晚,则在父进程结束后,子进程的父进程会变成pid为1 的进程

最终版本:

#include	"unp.h"int
main(int argc, char **argv)
{int					listenfd, connfd;pid_t				childpid;socklen_t			clilen;struct sockaddr_in	cliaddr, servaddr;void				sig_chld(int);listenfd = Socket(AF_INET, SOCK_STREAM, 0);bzero(&servaddr, sizeof(servaddr));servaddr.sin_family      = AF_INET;servaddr.sin_addr.s_addr = htonl(INADDR_ANY);servaddr.sin_port        = htons(SERV_PORT);Bind(listenfd, (SA *) &servaddr, sizeof(servaddr));Listen(listenfd, LISTENQ);/*按我现阶段的理解:(1)Signal捕获信号SIGCHLD,并交给sig_chld处理(2)Signal第二个参数实际上是一个函数指针,将sig_chld传入*//** sig_chld()函数解析:* 使用waitpid函数,并指定WNOHANG参数(有尚未终止的子进程是不要阻塞)* 为什么不适用wait函数,防止产生僵死进程,因为没有办法防止wait在正在运行的子进程尚有未终止阻塞(具体参见《unix网络编程》110页)* 阻塞:此处的阻塞不同于此前使用的同名词语,这里的阻塞是指阻塞信号或某个信号集,防止他们在阻塞期间提交。* 本节的目的是示范网络编程中可能遇到的情况:* (1)当fork某个进程时,必须捕获SIGCHLD信号* (2)当捕获信号时,必须处理被中断的系统调用* (3)SIGCHLD的信号处理函数必须正确编写,应使用waitpid函数以免留下僵死进程*/Signal(SIGCHLD, sig_chld);	/* must call waitpid() */for ( ; ; ){clilen = sizeof(cliaddr);if ( (connfd = accept(listenfd, (SA *) &cliaddr, &clilen)) < 0) {if (errno == EINTR)continue;		/* back to for() */elseerr_sys("accept error");}if ( (childpid = Fork()) == 0) {	/* child process */Close(listenfd);	/* close listening socket */str_echo(connfd);	/* process the request */exit(0);}Close(connfd);			/* parent closes connected socket */}
}

select()函数

#include "unp.h"#pragma clang diagnostic push
#pragma ide diagnostic ignored "EndlessLoop"void str_cli(FILE *fp, int sockfd) {//需要检查的文件描述符个数int maxfdp1;/* fd_set其实这是一个数组的宏定义,实际上是一long类型的数组,* 每一个数组元素都能与一打开的文件句柄(socket、文件、管道、设备等)建立联系,建立联系的工作由程序员完成,* 当调用select()时,由内核根据IO状态修改fd_set的内容,* 由此来通知执行了select()的进程哪个句柄可读。*/fd_set rset;char sendline[MAXLINE], recvline[MAXLINE];FD_ZERO(&rset);while (1) {//将fd加入set集合/** FD_CLR(int fd, fd_set *fdset);       //将fd从set集合中清除*FD_ISSET(int fd, fd_set *fdset);     //检测fd是否在set集合中,不在则返回0*FD_ZERO(fd_set *fdset);              //将set清零使集合中不含任何fd*///fileno()用来取得参数stream 指定的文件流所使用的文件描述词FD_SET(fileno(fp), &rset);//将套接字描述符加入集合FD_SET(sockfd, &rset);//为什么要加1呢:我们需要描述符的个数,而不是最大值,而描述符是从0开始的(妙吧!)maxfdp1 = max(fileno(fp), sockfd )+ 1;/*int select(int nfds,  fd_set* readset,  fd_set* writeset,  fe_set* exceptset,  struct timeval* timeout);* 参数:nfds           需要检查的文件描述字个数readset     用来检查可读性的一组文件描述字。writeset     用来检查可写性的一组文件描述字。exceptset  用来检查是否有异常条件出现的文件描述字。(注:错误不包括在异常条件之内)timeout      超时,填NULL为阻塞,填0为非阻塞,其他为一段超时时间返回值:返回fd的总数,错误时返回SOCKET_ERROR*/Select(maxfdp1, &rset, NULL, NULL, NULL);//FD_ISSET(int fd, fd_set *fdset);     //检测fd是否在set集合中,不在则返回0if (FD_ISSET(sockfd, &rset)) {if (Readline(sockfd, recvline, MAXLINE) == 0)err_quit("服务器超时");Fputs(recvline, stdout);}if (FD_ISSET(fileno(fp), &rset)) {if (Fgets(sendline, MAXLINE, fp) == NULL)return;Write(sockfd, sendline, strlen(sendline));}}}#pragma clang diagnostic pop
/* include fig01 */
#include	"unp.h"#pragma clang diagnostic push
#pragma ide diagnostic ignored "EndlessLoop"
int
main(int argc, char **argv)
{int					i, maxi, maxfd, listenfd, connfd, sockfd;int					nready, client[FD_SETSIZE];ssize_t				n;fd_set				rset, allset;char				buf[MAXLINE];socklen_t			clilen;struct sockaddr_in	cliaddr, servaddr;listenfd = Socket(AF_INET, SOCK_STREAM, 0);bzero(&servaddr, sizeof(servaddr));servaddr.sin_family      = AF_INET;servaddr.sin_addr.s_addr = htonl(INADDR_ANY);servaddr.sin_port        = htons(SERV_PORT);Bind(listenfd, (SA *) &servaddr, sizeof(servaddr));Listen(listenfd, LISTENQ);maxfd = listenfd;			/* 初始化 */maxi = -1;					/* index into client[] array *///将所有描述符初始化为-1for (i = 0; i < FD_SETSIZE; i++)client[i] = -1;			/* -1 indicates available entry */FD_ZERO(&allset);FD_SET(listenfd, &allset);
/* end fig01 *//* include fig02 */for ( ; ; ) {rset = allset;		/* structure assignment *///等待某个事件的发生nready = Select(maxfd+1, &rset, NULL, NULL, NULL);if (FD_ISSET(listenfd, &rset)) {	/* new client connection */clilen = sizeof(cliaddr);connfd = Accept(listenfd, (SA *) &cliaddr, &clilen);
#ifdef	NOTDEFprintf("new client: %s, port %d\n",Inet_ntop(AF_INET, &cliaddr.sin_addr, 4, NULL),ntohs(cliaddr.sin_port));
#endiffor (i = 0; i < FD_SETSIZE; i++)if (client[i] < 0) {client[i] = connfd;	/* 保存描述符 */break;/*保存了就跳出*/}if (i == FD_SETSIZE)err_quit("too many clients");FD_SET(connfd, &allset);	/*添加新的描述符来设置*/if (connfd > maxfd)maxfd = connfd;			/* for select */if (i > maxi)maxi = i;				/* max index in client[] array */if (--nready <= 0)continue;				/* no more readable descriptors */}for (i = 0; i <= maxi; i++) {	/* check all clients for data */if ( (sockfd = client[i]) < 0)continue;if (FD_ISSET(sockfd, &rset)) {if ( (n = Read(sockfd, buf, MAXLINE)) == 0) {/*4connection closed by client */Close(sockfd);FD_CLR(sockfd, &allset);client[i] = -1;} elseWriten(sockfd, buf, n);if (--nready <= 0)break;				/* no more readable descriptors */}}}}
/* end fig02 */
#pragma clang diagnostic pop

pselect()函数

函数select()是用一种超时轮循的方式来查看文件的读写错误可操作性。在Linux下,还有一个相似的函数pselect()。

poll()函数

int poll(struct pollfd *fds, nfds_t nfds, int timeout);

功能:
监视并等待多个文件描述符的属性变化
参数:

fds:指向一个结构体数组的第0个元素的指针,每个数组元素都是一个struct pollfd结构,用于指定测试某个给定的fd的条件

struct pollfd{int fd;			//文件描述符short events;	//等待的事件short revents;	//实际发生的事件
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/408226.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

oracle数据库中函数和存储过程中的区别

一、函数必须有返回值&#xff0c;过程没有返回值&#xff1b; 二、函数可以单独执行&#xff0c;过程必须通过execute执行&#xff1b; 三、函数可以嵌入SQL中执行&#xff0c;过程不能。 可以将比较复杂的查询写成函数&#xff0c;然后在过程中调用。转载于:https://www.cnbl…

百川2大模型微调问题解决

之前用https://github.com/FlagAlpha/Llama2-Chinese微调过几个模型&#xff0c;总体来说llama2的生态还是比较好的&#xff0c;过程很顺利。微调百川2就没那么顺利了&#xff0c;所以简单做个记录 1. 数据准备&#xff0c;我的数据是单轮对话&#xff0c;之前微调llama2已经按…

Aspx页面javascript的几个trick

1、一般而言&#xff0c;如果想给aspx页面上的web form control加上一些javascript的特性&#xff0c;可以用Attributes.Add来实现。例如&#xff0c;对TextBox txt&#xff0c;可以&#xff1a;txt.Attributes.Add("onclick", "fcn0();");那么&#xff0c…

ArcGIS 10——地理数据库管理GIS数据

写本文的最初意向是当前正在进行的项目中有实现ESRI版本化数据管理的功能模块&#xff0c;碰到一些棘手的问题&#xff0c;几经周折还是决定系统学习ArcGIS10的帮助文档。&#xff08;文章摘抄的比较多&#xff09; 地理数据库是用于保存数据集集合的“容器”。首先了解一下Arc…

阿特拉斯神(一)

Atlas出来很久了&#xff0c;因为用不上&#xff0c;所以没有学习过&#xff0c;今天准备学了&#xff0c;却发现资料虽不少&#xff0c;但是觉得有点乱&#xff0c;还是自己从英文资料循序渐进学吧。说真的没有扎实学过什么&#xff0c;那么就从Atlas开始吧&#xff0c;希望也…

Qt学习笔记(持续更新)

第一个应用程序 #include "widget.h" #include <QApplication> #include<QLabel> int main(int argc, char *argv[]) {//创建qt应用程序对象QApplication a(argc, argv);//创建标签控件QLabel label("你好");//来吧&#xff0c;展示label.sho…

文本框宽度自动适应文本宽度

<html> <head> <title>文本框宽度自动适应文本宽度 </title> </head> <script type"text/javascript"> function changeInputlength(cursor) { var getTextdocument.getElementById("text"); cursor.sizegetText.valu…

安装了一次Linux,哈哈

昨天在宿舍里&#xff0c;舍友在她的机子上装了Redhat&#xff0c;自己在旁边和另一舍友做参谋&#xff0c;哈哈&#xff0c;虽然中间几多挫折&#xff0c;但最终还是把系统装好了&#xff0c;第一次完整的安装Linux&#xff0c;在此记录一下&#xff0c;哈哈…… 现在想…

Ubuntu NFS搭建过程

简介 NFS:是Network FileSystem。最大的作用就是通过网络&#xff0c;让不同的机器、不同的作业系统、可以分享档案。通过将共享目录挂接到本地&#xff0c;就可以像操作本地目录一样去操作共享的目录。在共享中分为服务器和客户端,需要安装的程序也不一样&#xff0c;客户端通…

Unicode简介【转】

Unicode是一种字符编码规范 。先从ASCII说起。ASCII是用来表示英文字符的一种编码规范&#xff0c;每个ASCII字符占用1个字节&#xff08;8bits&#xff09; 因此&#xff0c;ASCII编码可以表示的最大字符数是256&#xff0c;其实英文字符并没有那么多&#xff0c;一般只用前12…

C++17新特性学习笔记

c17最新特性笔记 1.基本语言特性 ​ 这一部分介绍了 C17中新的核心语言特性&#xff0c;但不包括那些专为泛型编程&#xff08;即 template&#xff09;设计的特性。 结构化绑定 结构化绑定允许你用一个对象的元素或对象初始化多个实例(第一眼感觉Python解包很像) 这有一个…

教你如何写框架------用中文构建脚本

框架下载地址&#xff1a; http://files.cnblogs.com/zhangfei/Automation.rar 在看此篇博文前请先理清如下两下博文, 该博文是建立在如下两篇文章的基础上的&#xff1a; http://www.cnblogs.com/zhangfei/p/3456159.htmlhttp://www.cnblogs.com/zhangfei/archive/2012/10/10/…

配置MIME一览

用JSP写WML&#xff1a;Code:<% page contentType"text/vnd.wap.wml; charsetGBK" %> <?xml version"1.0"?> <!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN" "http://www.WAPforum.org/DTD/wml_1.1.xml"> …