Unix网络编程
学习C语言必看书籍
一部分大概与大学课程:计算机组成原理、计算机系统结构、汇编
等等相关,就是较浅地讲了讲组原、系统结构、汇编的内容,说
浅,是因为这本书讲的绝对没有课上讲的深。第二部分讲了链接、
虚存等等。第三部分讲了些应用的东西。这书是CMU的导论性质的
课的教材。个人最喜欢程序的机器级表示和虚拟存储器这两章。另
外,这本书和操作系统也基本上没关系,对比一下操作系统教材和
可以作为学习C的第二本书
C++语言
C缺陷和陷阱
可以作为学习C的第三或第四本书
C专家编程
可以作为学习C的第三或第四本书
数组与指针的艺 术
C语言深度解剖
supermegaboy写的。不错。 程正冲 编著,石虎 审阅。
C99标准
有问题时查一查,很多问题可迎 刃而解。
C的初级读物。如果读过C与指 彻底搞定C指针 针,可忽略。
阅读材料
有些书,想读。可惜现在没有时间 。只能断断续续的读。在淘宝上 找了个卖盗版书的店,因为价格比正版便宜很多,所以买了很多。 先放在桌子上,有时间再读。
1: C++ Primer中文版第四版。好好学这本书,秒杀趋势
华为中兴的笔试的C++部分。没有C语言基础的人,C++ Primer Plus 或许是更好的选择。
深入理解计算机 系统英文版
好书
深入理解计算机 系统中文版
好书
专业相关的东西:
计算机协议的 设计与验证
比较专业的东西,英文的,design and validation of computer protocols,学过计算机网络,TCP/IP再看 应该没有问题。第八章讲的是有限状态机,不错
Unix的Python编程
Unix的Python编程Unix操作系统和Python编程语言是现代计算机科学中最强大的工具之一。
Unix系统提供了一个强大而灵活的基础架构和命令行工具,与Python一起使用可以使开发人员更轻松地实现自己的项目。
本文将介绍Unix和Python之间的关系,以及如何在Unix上使用Python编程。
Unix的基础知识Unix是一种操作系统,它在70年代中期诞生于贝尔实验室。
它具有许多特殊功能,如虚拟文件系统,内存映射和磁盘缓存等,这些功能使Unix成为一个强大、高级的操作系统。
在Unix系统中,所有内容都被视为文件或者文件夹。
命令行是Unix的一个主要界面,人们可以轻松地通过键入命令执行各种操作。
与传统操作系统相比,Unix操作系统的一大优势在于它的灵活性和可定制性。
开发人员可以轻松地编写脚本和程序来利用Unix 系统。
Python的基础知识Python是一种高级编程语言,它在上世纪90年代诞生于荷兰。
Python的语法简单,可读性高,而且它支持许多编程范式,如面向对象编程、命令式编程和函数式编程。
Python具有许多特殊功能,如自动内存管理和广泛的标准库,使得它成为一个流行的编程语言。
Python被广泛应用于网络开发、数据分析、人工智能、机器学习和科学计算等领域。
Unix上的Python编程许多开发人员喜欢在Unix上使用Python编程。
Unix系统的灵活性和可定制性与Python的简明易读和可定制性相结合,使得Unix和Python成为完美的开发工具。
在Unix上,开发人员可以使用Python编写脚本来自动化各种任务。
Python和Unix的实用程序完美地配合,开发人员能够轻松地使用Python和Unix的命令行工具来编写脚本,提高效率和生产力。
此外,Python和Unix的核心值得注意的一点是它们都是开源和免费的。
这意味着开发人员可以在没有任何成本限制的情况下获得这些工具,这对于开发人员、初学者和新兴企业来说是一种很大的优势。
程序员技术练级攻略——程序员大牛进阶之路!
程序员技术练级攻略——程序员大牛进阶之路!你是否觉得自己从学校毕业的时候只做过小玩具一样的程序?走入职场后哪怕没有什么经验也可以把以下这些课外练习走一遍(朋友的抱怨:学校课程总是从理论出发,作业项目都看不出有什么实际作用,不如从工作中的需求出发)建议:不要乱买书,不要乱追新技术新名词,基础的东西经过很长时间积累而且还会在未来至少10年通用。
回顾一下历史,看看历史上时间线上技术的发展,你才能明白明天会是什么样。
一定要动手,例子不管多么简单,建议至少自己手敲一遍看看是否理解了里头的细枝末节。
一定要学会思考,思考为什么要这样,而不是那样。
还要举一反三地思考。
注:你也许会很奇怪为什么下面的东西很偏Unix/Linux,这是因为我觉得Windows下的编程可能会在未来很没有前途,原因如下:现在的用户界面几乎被两个东西主宰了,1)Web,2)移动设备iOS或Android。
Windows的图形界面不吃香了。
越来越多的企业在用成本低性能高的Linux和各种开源技术来构架其系统,Windows的成本太高了。
微软的东西变得太快了,很不持久,他们完全是在玩弄程序员。
详情参见《Windows编程革命史》所以,我个人认为以后的趋势是前端是Web+移动,后端是Linux+开源。
开发这边基本上没Windows什么事。
1、学习一门脚本语言,例如Python/Ruby可以让你摆脱对底层语言的恐惧感,脚本语言可以让你很快开发出能用得上的小程序。
实践项目:处理文本文件,或者csv (关键词python csv, python open, python sys) 读一个本地文件,逐行处理(例如 word count,或者处理log)遍历本地文件系统 (sys, os, path),例如写一个程序统计一个目录下所有文件大小并按各种条件排序并保存结果跟数据库打交道(python sqlite),写一个小脚本统计数据库里条目数量学会用各种print之类简单粗暴的方式进行调试学会用Google (phrase, domain, use reader to follow tech blogs)为什么要学脚本语言,因为他们实在是太方便了,很多时候我们需要写点小工具或是脚本来帮我们解决问题,你就会发现正规的编程语言太难用了。
unix网络编程之listen()详解
unix⽹络编程之listen()详解Unix⽹络编程描述如下: #include <sys/socket.h> int listen(int sockfd, int backlog); 返回:若成功则为0,若出错则为-1; 本函数通常应该在调⽤socket和bind这两个函数之后,并在调⽤accept函数之前调⽤;为了理解其中的backlog参数,我们必须认识到内核为任何⼀个给定的监听套接字维护两个队列: (1)未完成连接队列(incomplete connection queue),每个这样的SYN分节对应其中⼀项:已由某个客户发出并到达服务器,⽽服务器正在等待完成相应的TCP三次握⼿过程,这些套接字处于SYN_RCVD状态; (2)已完成连接队列(completed connection queue),每个已完成TCP三次握⼿过程的客户端对应其中⼀项。
这些套接字处于ESTABLISHED状态;总结: 1、accept()函数不参与三次握⼿,⽽只负责从建⽴连接队列中取出⼀个连接和socketfd进⾏绑定; 2、backlog参数决定了未完成队列和已完成队列中连接数⽬之和的最⼤值(从内核的⾓度,是否这个和就是等于sock->recv_queue ); 3、accept()函数调⽤,会从已连接队列中取出⼀个“连接”(可以说描述的数据结构listensocket->sock->recv_queue[sk_buff] ? ),未完成队列和已完成队列中连接数 ⽬之和将减少1;即accept将监听套接字对应的sock的接收队列中的已建⽴连接的sk_buff取下(从该sk_buff中可以获得对端主机的发送过来的tcp/ip数据包) 4、监听套接字的已完成队列中的元素个数⼤于0,那么该套接字是可读的。
5、当程序调⽤accept的时候(设置阻塞参数),那么判定该套接字是否可读,不可读则进⼊睡眠,直⾄已完成队列中的元素个数⼤于0(监听套接字可读)⽽唤起监听进程)。
网络编程笔记(一)-基本TCP套接字编程
⽹络编程笔记(⼀)-基本TCP套接字编程⽹络编程笔记(⼀)-基本TCP套接字编程参考《UNIX⽹络编程》1 - 4 章,《TCP/IP⽹络编程》1 - 5 章。
基础知识基本概念守护进程(daemon):⼀般认为 Web 服务器程序是⼀个长时间运⾏的程序,它只在响应来⾃⽹络的请求时才发送⽹络消息。
守护进程能在后台运⾏且不跟任何终端关联。
TCP 套接字的花哨名字:⽹际(AF_INET)字节流(SOCK_STREAM)套接字时间获取服务器的众所周知端⼝:13协议⽆关性:将 IPv4 修改为 IPv6 协议sockaddr_in ——> sockaddr_in6AF_INET ——> AF_INET6sin_port ——> sin6_port更好的做法是编写协议⽆关程序。
包裹函数weapper function。
在本书中,约定包裹函数名是实际函数名的⾸字母⼤写形式。
每个包裹函数完成实际的函数调⽤,检查返回值,并在错误时终⽌进程。
int Socket(int family, int type, int protocol){int n;if( (n = socket(family, type, protocol)) < 0)err_sys("socket error");return(n);}Unix errno 值:只要有⼀个 UNIX 函数中有错误发⽣,全局变量 errno 就被置为⼀个指明该错误类型的正值,函数本⾝则通常返回 -1。
err_sys(作者定义的)查看 errno 变量的值并输出相应的出错信息。
服务器种类:迭代服务器:对于每个客户都迭代执⾏⼀次并发服务器:同时处理多个客户(Unix 的 fork 函数,⽤线程替代 fork 等)国际标准化组织(International Organization for Standardization,ISO)的计算机通信开放系统互连模型(open systemsinterconnection,OSI),是⼀个七层模型。
pthread_exit参数
pthread_exit参数pthread_exit函数是线程库中的一个函数,其作用是终止当前线程并返回一个指定的退出状态。
这个退出状态可以被其他线程通过pthread_join函数获取到。
pthread_exit的参数是一个指向线程的退出状态的指针。
pthread_exit函数的原型如下:```cvoid pthread_exit(void *retval);```参数retval是指向线程退出状态的指针。
该状态可以被其他线程通过pthread_join函数获取。
pthread_exit函数会阻塞当前线程,直到其他线程调用pthread_join函数或者主线程结束。
如果当前线程是主线程,那么调用pthread_exit函数等同于调用exit函数,会终止整个进程。
以下是pthread_exit函数的一些参考内容:1. 《UNIX网络编程卷一:套接字联网API》这本书是经典的UNIX网络编程指南,第11章介绍了线程的创建和终止。
其中有关于pthread_exit的用法和示例代码。
2. 《Linux/UNIX系统编程手册》这本书是UNIX/Linux系统编程的权威参考书,第31章介绍了线程的控制以及pthread库的使用。
其中涵盖了pthread_exit 函数的详细说明和示例代码。
3. 《POSIX线程编程》这本书详细介绍了POSIX线程编程的各个方面。
其中第6章介绍了线程控制和退出,包括pthread_exit函数的用法和示例。
4. 《Advanced Programming in the UNIX Environment》这本书是UNIX环境高级编程的经典之作,第12章介绍了线程控制和终止。
其中对pthread_exit函数有详细的解释和示例代码。
5. 《Linux多线程服务端编程》这本书主要介绍了在Linux环境下进行多线程服务端编程的相关知识。
其中有关于pthread_exit函数的用法和示例代码,以及与其他相关函数的关系和比较。
unix domain socket 原理
unix domain socket 原理
Unix domain socket(也称为Unix域套接字)是一种特殊类型的套接字,用于在同一台服务器上的不同进程之间进行通信。
以下是Unix domain socket的原理:
1.创建套接字:首先,进程为Unix domain socket创建一个套接字,调用socket
函数来创建一个文件描述符(即套接字描述符)。
在创建套接字时,需要指定协议族为AF_UNIX(或AF_LOCAL),表示使用Unix域套接字。
2.绑定地址:进程将套接字绑定到一个本地地址上,该地址由文件系统中的一个
路径名标识。
这样,其他进程可以通过该路径名找到并连接到这个套接字。
3.建立连接:当其他进程想要与该套接字建立连接时,它会通过相同的路径名找
到该套接字,并尝试与其建立连接。
一旦连接建立,两个进程就可以通过套接字进行通信。
4.数据传输:Unix domain socket使用流式数据传输方式,这意味着数据可以
在两个进程之间连续地、双向地传输。
数据以字节流的形式通过套接字传输,可以不受限制地发送任意大小的数据。
5.关闭连接:当通信完成或不再需要时,进程可以关闭套接字连接。
关闭连接后,
该套接字占用的资源将被释放,以便其他进程可以使用相同的路径名创建新的套接字连接。
总之,Unix domain socket的原理是基于文件描述符的,每个进程都拥有一个唯一的文件描述符,用于标识一个打开的文件或者套接字。
通过使用Unix domain socket,进程可以在同一台服务器上方便地进行通信,无需通过网络协议进行数据传输。
unix link文件语句
unix link文件语句Unix link是一种在Unix操作系统中创建链接文件的命令,它可以让用户在不同的目录中创建相同文件的链接。
下面是一些关于Unix link文件语句的例子,它们符合以上要求:1. 创建硬链接:- 使用ln命令创建硬链接文件:ln file1 file2- 创建一个名为linkfile的硬链接:ln -s file1 linkfile2. 删除链接文件:- 删除硬链接文件:rm file2- 删除软链接文件:rm linkfile3. 查看链接文件的信息:- 使用ls命令查看链接文件的信息:ls -l4. 修改链接文件的目标文件:- 修改硬链接文件的目标文件:ln -f -s file3 linkfile5. 查找链接文件的目标文件:- 使用readlink命令查找软链接文件的目标文件:readlink linkfile6. 复制链接文件:- 复制硬链接文件:cp -l file2 file2_copy- 复制软链接文件:cp -s linkfile linkfile_copy7. 移动链接文件:- 移动硬链接文件:mv file2 dir1/- 移动软链接文件:mv linkfile dir2/8. 创建目录链接:- 使用ln命令创建目录的硬链接:ln -d dir1 dir2- 创建一个名为linkdir的目录软链接:ln -s dir1 linkdir9. 修改链接文件的权限:- 使用chmod命令修改链接文件的权限:chmod 755 linkfile10. 查找链接文件:- 使用find命令查找链接文件:find / -name linkfile这些例子展示了如何使用Unix link文件语句来创建、删除、修改、复制和移动链接文件,以及如何查找链接文件和修改链接文件的权限。
它们使用简洁明了的语言描述了具体的操作步骤,避免了使用数学公式、网络地址、图片链接和依赖图像的语句,同时保持了文章的逻辑结构和阅读流畅性。
计算机运维书籍
计算机运维书籍计算机运维相关的书籍有很多,以下是一些值得推荐的书籍:《鸟哥的私房菜(基础篇)》、《鸟哥的私房菜(服务篇)》。
这两本适合新手入门,有助于了解Linux的基础知识和服务配置。
《Linux命令行与Shell脚本编程大全(第2版)》。
这本书涵盖了Linux命令行与Shell脚本编程的方方面面,对于希望深入了解Linux命令和Shell 脚本的用户来说是一本非常不错的参考书。
《UNIX/Linux 系统管理技术手册》。
这本书从系统管理的角度深入地介绍了UNIX/Linux系统的各种知识和技术,对于希望成为系统管理员的用户来说是一本非常有价值的参考书。
《深入理解计算机系统(原书第2版)》、《现代操作系统 (原书第3版)》。
这两本书是计算机系统与操作系统领域的经典著作,有助于深入理解计算机系统与操作系统的底层原理和工作机制。
《Linux内核设计与实现(原书第3版)》、《Linux程序设计(第4版)》。
这两本书从内核设计和程序设计的角度深入地介绍了Linux系统的实现原理和工作机制,对于希望深入了解Linux系统的用户来说是非常有价值的参考书。
《UNIX网络编程卷1:套接字联网API(第3版)》、《UNIX网络编程卷2:进程间通信(第2版)》。
这两本书是介绍UNIX网络编程的经典著作,从套接字编程和进程间通信的角度深入地介绍了UNIX网络编程的各种技术和API,对于希望进行网络编程的用户来说是非常有价值的参考书。
《UNIX环境高级编程(第2版)》。
这本书是介绍UNIX环境编程的经典著作,从系统调用和C语言的角度深入地介绍了UNIX环境编程的各种技术和API,对于希望进行系统级编程的用户来说是一本非常有价值的参考书。
《Linux设备驱动程序(第三版)》。
这本书是介绍Linux设备驱动开发的经典著作,从内核模块和设备驱动的角度深入地介绍了Linux设备驱动开发的各种技术和技巧,对于希望进行设备驱动开发的用户来说是一本非常有价值的参考书。
unix系统编程man手册
unix系统编程man手册摘要:1.Unix 系统编程概述2.Man 手册的含义和作用3.Man 手册的结构和内容4.Man 手册的查阅方法5.Man 手册在系统编程中的应用正文:【Unix 系统编程概述】Unix 系统编程是指在Unix、Linux 等类Unix 操作系统上进行程序开发的过程。
这类操作系统具有开放性、可扩展性和稳定性等特点,广泛应用于服务器、嵌入式系统等领域。
Unix 系统编程涉及多种编程语言,如C、C++等,以及操作系统提供的各种系统调用和库函数。
【Man 手册的含义和作用】Man 手册,全称Manual,是Unix 系统中一份详细的在线文档,包含了系统调用、库函数、命令行工具等的使用方法和相关信息。
它对于系统编程者来说是非常重要的参考资料,可以帮助程序员更好地了解和掌握系统编程的方法和技术。
【Man 手册的结构和内容】Man 手册通常采用一种称为“manpage”的格式编写,每个manpage 对应一个特定的系统调用或函数。
manpage 分为几部分,主要包括:1.概述(Synopsis):简要介绍该系统调用或函数的作用、功能和参数。
2.参数(Parameters):详细说明该系统调用或函数所需的参数及其类型、含义等。
3.返回值(Return Values):描述该系统调用或函数可能返回的值及其含义。
4.错误(Errors):列举可能出现的错误及其原因和处理方法。
5.示例(Examples):给出使用该系统调用或函数的典型示例。
6.备注(Notes):说明一些特殊的注意事项和使用技巧。
7.见诸(SEE ALSO):列出与该系统调用或函数相关的其他manpages。
【Man 手册的查阅方法】在Unix 系统中,有多种方法可以查阅Man 手册。
常用的命令行工具包括:1.man:直接在终端输入man 命令,后面跟上要查询的系统调用或函数名,如“man sys_ni_syscall”。
UNIUNIX教程网络篇
U N I U N I X教程网络篇 Prepared on 22 November 2020下载第2章电子邮件程序mailx使用mailx程序,用户可以方便地收发信件。
当你发送信件时,只要输入一个登录名然后接着输入信件正文就可以了;在接收阅读信件时,只需要在接收信件列表中选中一封信件即可。
mailx是一个非常灵活而精致的程序,具有许多不同的功能。
当用户发送信件时,可以使用很多命令来修改信件的正文,还可以撰写信件头。
当用户接受信件时,可以立即回复作者,并将信件保存在文件中,或者删除掉。
另外,它还设了一个初始化文件,名叫.mailrc,用来配置诸如别名等一些有关邮件程序的特性。
mailx程序还具有网络寻址功能,可以方便地用来向网络中的另一个系统上的用户发送信件。
在不同的Unix版本中,mailx命令具有不同的程序名。
它最早是由Eric Allman为BSD Unix开发出来的,最初就叫做mail(在System V Unix早期的版本中也有一种叫mail的简单邮件程序)。
在System V后来的版本中,也采用了BSD中的邮件程序,并将它改名为mailx。
发送信件使用mailx发送的信件内容,可以即时通过键盘输入,或者是事先准备好的一个文件中的内容。
如果通过键盘输入,可以采用特殊的tilde命令对内容进行编辑。
使用mailx发送信件时,在命令行中输入mailx,并指明信件接收者的地址。
敲回车键(Enter)后,系统提示输入Subject(主题)。
输入完Subject并敲回车键后,系统进行文本输入模式,在这期间键入的任何字符都将作为信件的内容。
如果输入回车键,就结束当前行而进入新的一行。
信件内容输入完毕后,键入Ctrl-d就开始发送信件,然后屏幕上会显示EOT字样,表示信件传送结束。
在下面的示例中,用户向地址为dylan的另一个用户发送信件,信件的主题是Game。
键入信件正文后,用户应按Ctrl-d。
UNIX网络编程卷1,套接字联网API(第3版)(中文版)(Stun
UNIX网络编程.卷1,套接字联网API(第3版)(中文版)(Stun UNIX网络编程.卷1,套接字联网API(第3版)(中文版)(StunUNIX网络编程.卷1,套接字联网API(第3版)(中文版)(StunUNIX网络编程.卷1,套接字联网API(第3版)(中文版)(Stevens典范著作,两位顶级网络编程专家应邀执笔订正)基础新闻原书名:unix网络编程 chm。
UnixNetworkProgramming,Volume1:TheSocketsNetworkingAPI(3rdEdition)原出版社:你看java网络编程技术。
Addison-WesleyProfessional作者:(美)W.RichardStevensBillFennerAndrewM.Rudoff丛书名:linux网络编程。
图灵计算机迷信丛书出版社:我不知道计算机网络编程技术。
百姓邮电出版社ISBN上架光阴:unix网络编程 chm。
2010-6-28出版日期:听说stun。
2010年6月开本:16开页码:听听unix网络编程 卷2。
804更多精华周详信息请审查:你知道计算机网络编程技术。
更有精彩样张抢先试读:unix网络编程 osock_cmp_addr形式简介这是一部传世之作!顶级网络编程专家BillFenner和AndrewM.Rudoff应邀执笔,事实上UNIX网络编程。
对W.RichardStevens的经典作品实行修订。
java网络编程 pdf。
书中吸纳了近几年网络技术的进展,卷1。
扩充了IPv6、SCTP协议和密钥管理套接字等外容,java网络编程技术。
深刻谈论了最新的关键轨范、实行和技术。
书中的全盘示例都是在UNIX编制上测试议定的的确的、可运转的代码,卷1。
承受了Stevens继续强调的理念:“练习网络编程的最好方法就是下载这些程序,看看java网络游戏编程。
其实unix。
对其进行改正和更正。
听说编程。
Unix网络编程-端口号及缓冲区限制
TCP端口号多个进程可能同时使用TCP、UDP传输层协议来进行数据传输,传输层怎样知道要送给哪个进程呢?端口号由此产生,用来标识这些进程。
通常服务端,TCP、UDP会使用众所周知的端口来标识服务,举例来说,支持FTP的任何TCP/IP实现都是把21这个众所周知的端口分配给FTP服务。
分配给简化文件传输协议TFTP的是UDP端口号69。
通常客户端,使用短期存活的临时端口。
这些端口通常由传输层协议自动赋予客户端。
客户端通常不关心其临时端口的具体值,而只需该端口在此主机中是唯一的就性。
传输协议的代码确保这种唯一性。
端口号被划分为一下3段。
1)众所周知的端口为0 ~1023。
这些端口由**分配和控制。
可能的话,相同端口号就分配给TCP、UDP、和SCTP的同一给定服务。
例如,不论TCP还是UDP端口号80都被赋予web服务器2)已登记的端口为1024 ~49151。
这些端口不受**控制,不过由**登记并提供他们的使用情况清单,以方便整个群体。
可能的话,相同端口号也分配给TCP和UDP的同一给定服务。
3)49152 ~ 65535是动态的或私用的端口。
IANA不管这些端口。
他们就是我们所称的临时端口。
上图展示了端口号的划分情况和常见的分配情况。
a)Unix系统有保留端口的概念(reserved port)的概念,指的是小于1024的任何端口。
这些端口只能赋予特权用户进程的套接字。
所有IANA众所周知的端口都是保留端口,分配使用这些端口的服务器必须以超级用户特权启动。
b)由于历史原因,源自Berkeley的实现曾在1024~5000范围内分配临时端口。
这在20世纪80年代初期是可行的,但是如今很容易找到一个在任何给定世纪内同时支持多于3977个连接的主机。
于是许多较新的系统从另外的范围分配临时端口以提供更多的临时端口,他们或者使用由IANA定义的临时端口范围,或者使用一个更大的其他范围。
(如上图的solaris)。
unix环境高级编程 pdf
unix环境高级编程UNIX环境高级编程是一本经典的计算机操作系统书籍,也是许多程序员必备的一本书。
这本书中涵盖了各种UNIX环境下的高级编程技术和方法,涵盖的内容非常广泛,涉及到很多重要的主题,比如进程和线程、文件IO、信号处理、进程间通信、网络编程、套接字编程等。
这本书特别重视实践,全书中包括了很多实例代码,让读者通过实际操作能够更好地理解书中所讲的知识。
同时,书中也有很多经典案例的介绍,这些案例都是具有代表性的程序,可以让读者更好地了解UNIX环境下的高级编程技术。
在进程和线程方面,本书介绍了进程的基本概念和进程控制、进程环境、线程等相关知识。
同时还讲解了如何使用进程控制函数,如fork、exec和wait等。
通过这些基本的控制函数,程序员可以更好地管理和控制进程和线程的行为。
在文件IO方面,本书讲解了文件描述符和文件IO函数的使用,比如open、read、write和close。
通过这些函数,程序员可以实现对文件的读写操作,同时还讲解了如何使用文件锁定等相关知识。
在信号处理方面,本书详细讲解了信号的基本概念,信号的发送和接收,信号的处理等。
同时还介绍了如何使用信号进行进程间的通信,如何使用信号来处理异常情况等。
在进程间通信方面,本书讲解了进程间通信的机制和方法,如管道、FIFO、共享内存、消息队列等。
这些技术都是在UNIX环境下比较常用的通信方式,可以让程序员更好地实现进程间的数据交换和协作。
在网络编程方面,本书深入介绍了套接字的概念和使用方法,讲解了TCP和UDP协议的特点和使用方法,以及如何使用套接字进行网络编程。
总的来说,UNIX环境高级编程是一本非常经典的计算机操作系统书籍,它涵盖了对UNIX环境下高级编程技术的全面介绍,对于想要深入了解UNIX环境下编程的程序员来说是一本不可缺少的书。
unix 教程
8
Unix成为一种软件商品后, Unix成为一种软件商品后,其源代码也就不再随 成为一种软件商品后 意公开。Andrew S. Tanenbaum教授在Unix的基础 意公开。 Tanenbaum教授在Unix的基础 教授在Unix 上开发了教学版的Unix 取名MInix 意为Mini Unix, MInix, Mini上开发了教学版的Unix,取名MInix,意为MiniUnix。 Unix。 1991年 芬兰学生Linus Torvalds, 1991年,芬兰学生Linus Benedict Torvalds,在 PC上独立编写了基于Intel 80386体系结构的Unix PC上独立编写了基于Intel 80386体系结构的Unix 上独立编写了基于 体系结构的 系统,名为Linux Linux。 系统,名为Linux。世界各地的软件爱好者都可以 通过Internet免费获得Linux Internet免费获得Linux的全部源代码和二进 通过Internet免费获得Linux的全部源代码和二进 制发行版本。现在,Linux更是发展迅速 从比PC 更是发展迅速。 制发行版本。现在,Linux更是发展迅速。从比PC 还要简单得多的小型嵌入式环境, 还要简单得多的小型嵌入式环境,一直到大型的 服务器,都有Linux操作系统在运行。 Linux操作系统在运行 服务器,都有Linux操作系统在运行。
unix操作系统概述 第2单元 第一章 unix操作系统概述
6
◇早期的Internet上的大部分计算机都运行Unix。两 早期的Internet上的大部分计算机都运行Unix。 Internet上的大部分计算机都运行Unix 种流派的Unix随着不断的发展, 种流派的Unix随着不断的发展,互相吸收对方的新 Unix随着不断的发展 技术,趋于统一到逐渐完备的POSIX标准。 技术,趋于统一到逐渐完备的POSIX标准。 POSIX标准
Unix编程艺术:掌握Unix下的编程技巧
Unix编程艺术:掌握Unix下的编程技巧Unix编程艺术是一门非常重要的技能,在Unix操作系统下进行编程开发是许多程序员的首选。
Unix系统提供了强大的工具和环境,能够让开发者更高效地完成工作。
掌握Unix编程艺术可以让开发者更加灵活地处理复杂的问题,提高编程效率和质量。
在这篇文章中,我将介绍一些Unix编程的技巧和方法,帮助读者更好地掌握Unix编程艺术。
一、熟练掌握Shell编程Shell编程是Unix系统中最基本的编程语言,通过Shell编程可以进行系统管理、脚本编写等工作。
熟练掌握Shell编程可以帮助开发者更好地理解Unix系统的工作原理,提高工作效率。
在编写Shell 脚本时,需要注意以下几点:1.确保脚本可读性强:合理命名变量和函数,使用注释解释代码逻辑,提高代码的可维护性。
2.处理错误和异常情况:编写脚本时需要考虑各种错误和异常情况,并进行合理的处理,确保程序的稳定性。
3.使用合适的工具和技巧:在Shell编程中,可以使用诸如grep、awk、sed等工具来处理文本数据,提高处理效率。
二、熟练使用管道和重定向在Unix系统中,管道和重定向是非常重要的特性,可以帮助开发者更好地处理输入输出流。
熟练使用管道和重定向可以大大提高工作效率,特别是在处理大量数据时更为重要。
一些常见的使用技巧包括:1.使用管道连接多个命令:通过管道可以将多个命令的输出连接起来,完成数据的传递和处理。
2.使用重定向控制输入输出:通过重定向可以控制命令的输入输出,如将命令的输出保存到文件或者从文件中读取。
3.使用管道和重定向强大的数据处理能力:通过结合使用管道和重定向,可以实现复杂的数据处理操作,灵活应对各种需求。
三、合理使用环境变量和别名Unix系统中的环境变量和别名是非常便捷的工具,在编程过程中可以大大简化操作。
合理使用环境变量和别名可以减少重复工作、提高效率。
一些常见的使用技巧包括:1.设置常用环境变量:设置一些常用的环境变量,如路径、编辑器等,可以减少重复输入。
UNIX基础教程
UNIX基础教程UNIX是一种多用户、多任务操作系统,广泛用于Unix-like的操作系统中。
它提供了一个强大且灵活的环境,适用于各种不同的应用程序和领域。
本教程将介绍UNIX的基础知识,包括文件系统、命令行界面、进程管理和网络通信等。
一、文件系统UNIX的文件系统是以层次化的目录结构来组织文件和目录。
用户可以使用命令对文件进行创建、删除、移动和复制等操作。
1.目录结构:UNIX的目录结构以根目录(/)为起点,所有的文件和目录都从根目录开始。
2. 目录操作:用户可以使用命令如cd、ls、mkdir和rmdir等来操作目录。
cd用于切换目录,ls用于列出目录内容,mkdir用于创建目录,rmdir用于删除空目录。
3. 文件操作:用户可以使用命令如cat、cp、mv和rm等来操作文件。
cat用于查看文件内容,cp用于复制文件,mv用于移动文件,rm用于删除文件。
二、命令行界面UNIX的命令行界面是用户与系统交互的主要方式。
用户可以通过输入命令来执行各种操作。
1.命令格式:UNIX的命令由命令名称和选项参数组成。
选项参数用于修改命令的行为,可以是单个字符或长参数。
2. 常用命令:UNIX提供了许多常用的命令,如基本的文件和目录操作命令,如ls、cd、mkdir和rmdir;文件查找和文本处理命令,如find、grep和sed;系统信息和管理命令,如ps、df和top等。
3.命令提示符:UNIX的命令行界面会显示一个命令提示符,用户可以在提示符后输入命令。
通常,命令提示符由当前用户名和主机名组成。
三、进程管理UNIX支持多任务操作,可以同时执行多个程序。
用户可以使用命令来管理进程和程序。
1. 运行程序:用户可以使用命令如./和exec等来运行程序。
./用于运行当前目录下的可执行文件,exec用于替换当前进程并执行新程序。
2. 后台运行:用户可以使用命令如&和nohup等将程序置于后台运行。
&用于将程序放入后台运行,nohup用于使程序在用户注销后继续运行。
unix网络编程
[size=16]UNIX网络编程[/size]1.1 客户端程序和服务端程序网络程序和普通的程序有一个最大的区别是网络程序是由两个部分组成的--客户端和服务器端.网络程序是先有服务器程序启动,等待客户端的程序运行并建立连接.一般的来说是服务端的程序在一个端口上监听,直到有一个客户端的程序发来了请求.1.2 常用的命令由于网络程序是有两个部分组成,所以在调试的时候比较麻烦,为此我们有必要知道一些常用的网络命令netstat命令netstat是用来显示网络的连接,路由表和接口统计等网络的信息.netstat有许多的选项我们常用的选项是-an 用来显示详细的网络状态.至于其它的选项我们可以使用帮助手册获得详细的情况.telnettelnet是一个用来远程控制的程序,但是我们完全可以用这个程序来调试我们的服务端程序的. 比如我们的服务器程序在监听8888端口,我们可以用telnet localhost 8888来查看服务端的状况.1.3 TCP/UDP介绍TCP(Transfer Control Protocol)传输控制协议是一种面向连接的协议,当我们的网络程序使用这个协议的时候,网络可以保证我们的客户端和服务端的连接是可靠的,安全的.UDP(User Datagram Protocol)用户数据报协议是一种非面向连接的协议,这种协议并不能保证我们的网络程序的连接是可靠的,所以我们现在编写的程序一般是采用TCP协议的.2. 初等网络函数介绍(TCP)unix系统是通过提供套接字(socket)来进行网络编程的.网络程序通过socket和其它几个函数的调用,会返回一个通讯的文件描述符,我们可以将这个描述符看成普通的文件的描述符来操作,这就是unix的设备无关性的好处.我们可以通过向描述符读写操作实现网络之间的数据交流.2.1 socketint socket(int domain, int type,int protocol)domain:说明我们网络程序所在的主机采用的通讯协族(AF_UNIX和AF_INET等). AF_UNIX只能够用于单一的Unix系统进程间通信,而AF_INET是针对Internet的,因而可以允许在远程主机之间通信(当我们man socket时发现domain可选项是PF_*而不是AF_*,因为glibc是posix的实现所以用PF代替了AF,不过我们都可以使用的).type:我们网络程序所采用的通讯协议(SOCK_STREAM,SOCK_DGRAM等) SOCK_STREAM表明我们用的是TCP协议,这样会提供按顺序的,可靠,双向,面向连接的比特流. SOCK_DGRAM 表明我们用的是UDP协议,这样只会提供定长的,不可靠,无连接的通信.protocol:由于我们指定了type,所以这个地方我们一般只要用0来代替就可以了socket为网络通讯做基本的准备.成功时返回文件描述符,失败时返回-1,看errno可知道出错的详细情况.2.2 bindint bind(int sockfd, struct sockaddr *my_addr, int addrlen)sockfd:是由socket调用返回的文件描述符.addrlen:是sockaddr结构的长度.my_addr:是一个指向sockaddr的指针. 在<unix/socket.h>;中有sockaddr的定义struct sockaddr{unisgned short as_family;char sa_data[14];};不过由于系统的兼容性,我们一般不用这个头文件,而使用另外一个结构(struct sockaddr_in) 来代替.在<unix/in.h>;中有sockaddr_in的定义struct sockaddr_in{unsigned short sin_family;unsigned short int sin_port;struct in_addr sin_addr;unsigned char sin_zero[8];我们主要使用Internet所以sin_family一般为AF_INET,sin_addr设置为INADDR_ANY 表示可以和任何的主机通信,sin_port是我们要监听的端口号.sin_zero[8]是用来填充的. bind将本地的端口同socket返回的文件描述符捆绑在一起.成功是返回0,失败的情况和socket一样2.3 listenint listen(int sockfd,int backlog)sockfd:是bind后的文件描述符.backlog:设置请求排队的最大长度.当有多个客户端程序和服务端相连时, 使用这个表示可以介绍的排队长度. listen函数将bind的文件描述符变为监听套接字.返回的情况和bind一样.2.4 acceptint accept(int sockfd, struct sockaddr *addr,int *addrlen)sockfd:是listen后的文件描述符.addr,addrlen是用来给客户端的程序填写的,服务器端只要传递指针就可以了. bind,listen 和accept是服务器端用的函数,accept调用时,服务器端的程序会一直阻塞到有一个客户程序发出了连接. accept成功时返回最后的服务器端的文件描述符,这个时候服务器端可以向该描述符写信息了. 失败时返回-12.5 connectint connect(int sockfd, struct sockaddr * serv_addr,int addrlen)sockfd:socket返回的文件描述符.serv_addr:储存了服务器端的连接信息.其中sin_add是服务端的地址addrlen:serv_addr的长度connect函数是客户端用来同服务端连接的.成功时返回0,sockfd是同服务端通讯的文件描述符失败时返回-1.2.6 实例服务器端程序/******* 服务器程序(server.c) ************/#include <stdlib.h>;#include <stdio.h>;#include <errno.h>;#include <string.h>;#include <netdb.h>;#include <sys/types.h>;#include <netinet/in.h>;#include <sys/socket.h>;int main(int argc, char *argv[]){int sockfd,new_fd;struct sockaddr_in server_addr;struct sockaddr_in client_addr;int sin_size,portnumber;char hello[]="Hello! Are You Fine?\n";if(argc!=2){fprintf(stderr,"Usage:%s portnumber\a\n",argv[0]); exit(1);}if((portnumber=atoi(argv[1]))<0){fprintf(stderr,"Usage:%s portnumber\a\n",argv[0]); exit(1);}/* 服务器端开始建立socket描述符*/if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1) {fprintf(stderr,"Socket error:%s\n\a",strerror(errno)); exit(1);}/* 服务器端填充sockaddr结构*/bzero(&server_addr,sizeof(struct sockaddr_in));server_addr.sin_family=AF_INET;server_addr.sin_addr.s_addr=htonl(INADDR_ANY);server_addr.sin_port=htons(portnumber);/* 捆绑sockfd描述符*/if(bind(sockfd,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr))==-1) {fprintf(stderr,"Bind error:%s\n\a",strerror(errno));exit(1);}/* 监听sockfd描述符*/if(listen(sockfd,5)==-1){fprintf(stderr,"Listen error:%s\n\a",strerror(errno));exit(1);}{/* 服务器阻塞,直到客户程序建立连接*/sin_size=sizeof(struct sockaddr_in);if((new_fd=accept(sockfd,(struct sockaddr *)(&client_addr),&sin_size))==-1) {fprintf(stderr,"Accept error:%s\n\a",strerror(errno));exit(1);}fprintf(stderr,"Server get connection from %s\n",inet_ntoa(client_addr.sin_addr));if(write(new_fd,hello,strlen(hello))==-1){fprintf(stderr,"Write Error:%s\n",strerror(errno));exit(1);}/* 这个通讯已经结束*/close(new_fd);/* 循环下一个*/}close(sockfd);}客户端程序/******* 客户端程序client.c ************/ #include <stdlib.h>;#include <stdio.h>;#include <errno.h>;#include <string.h>;#include <netdb.h>;#include <sys/types.h>;#include <netinet/in.h>;#include <sys/socket.h>;int main(int argc, char *argv[]){int sockfd;char buffer[1024];struct sockaddr_in server_addr;struct hostent *host;int portnumber,nbytes;if(argc!=3){fprintf(stderr,"Usage:%s hostname portnumber\a\n",argv[0]); exit(1);}if((host=gethostbyname(argv[1]))==NULL){fprintf(stderr,"Gethostname error\n");exit(1);}if((portnumber=atoi(argv[2]))<0){fprintf(stderr,"Usage:%s hostname portnumber\a\n",argv[0]); exit(1);}/* 客户程序开始建立sockfd描述符*/if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1){fprintf(stderr,"Socket Error:%s\a\n",strerror(errno));exit(1);}/* 客户程序填充服务端的资料*/bzero(&server_addr,sizeof(server_addr));server_addr.sin_family=AF_INET;server_addr.sin_port=htons(portnumber);server_addr.sin_addr=*((struct in_addr *)host->;h_addr);/* 客户程序发起连接请求*/if(connect(sockfd,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr))==-1) {fprintf(stderr,"Connect Error:%s\a\n",strerror(errno));exit(1);}/* 连接成功了*/if((nbytes=read(sockfd,buffer,1024))==-1){fprintf(stderr,"Read Error:%s\n",strerror(errno));exit(1);}buffer[nbytes]='\0';printf("I have received:%s\n",buffer);/* 结束通讯*/close(sockfd);exit(0);}MakeFile这里我们使用GNU 的make实用程序来编译. 关于make的详细说明见Make 使用介绍######### Makefile ###########all:server clientserver:server.cgcc $^ -o $@client:client.cgcc $^ -o $@运行make后会产生两个程序server(服务器端)和client(客户端) 先运行./server portnumber& (portnumber随便取一个大于1204且不在/etc/services中出现的号码就用8888好了),然后运行 ./client localhost 8888 看看有什么结果. (你也可以用telnet和netstat试一试.) 上面是一个最简单的网络程序,不过是不是也有点烦.上面有许多函数我们还没有解释. 我会在下一章进行的详细的说明.2.7 总结总的来说网络程序是由两个部分组成的--客户端和服务器端.它们的建立步骤一般是:服务器端socket-->;bind-->;listen-->;accept客户端socket-->;connect3. 服务器和客户机的信息函数这一章我们来学习转换和网络方面的信息函数.3.1 字节转换函数在网络上面有着许多类型的机器,这些机器在表示数据的字节顺序是不同的, 比如i386芯片是低字节在内存地址的低端,高字节在高端,而alpha芯片却相反. 为了统一起来,在unix下面,有专门的字节转换函数.unsigned long int htonl(unsigned long int hostlong)unsigned short int htons(unisgned short int hostshort)unsigned long int ntohl(unsigned long int netlong)unsigned short int ntohs(unsigned short int netshort)在这四个转换函数中,h 代表host, n 代表network.s 代表short l 代表long 第一个函数的意义是将本机器上的long数据转化为网络上的long. 其他几个函数的意义也差不多.3.2 IP和域名的转换在网络上标志一台机器可以用IP或者是用域名.那么我们怎么去进行转换呢?struct hostent *gethostbyname(const char *hostname)struct hostent *gethostbyaddr(const char *addr,int len,int type)在<netdb.h>;中有struct hostent的定义struct hostent{char *h_name; /* 主机的正式名称*/char *h_aliases; /* 主机的别名*/int h_addrtype; /* 主机的地址类型AF_INET*/int h_length; /* 主机的地址长度对于IP4 是4字节32位*/char **h_addr_list; /* 主机的IP地址列表*/}#define h_addr h_addr_list[0] /* 主机的第一个IP地址*/gethostbyname可以将机器名(如)转换为一个结构指针.在这个结构里面储存了域名的信息gethostbyaddr可以将一个32位的IP地址(C0A80001)转换为结构指针.这两个函数失败时返回NULL 且设置h_errno错误变量,调用h_strerror()可以得到详细的出错信息3.3 字符串的IP和32位的IP转换.在网络上面我们用的IP都是数字加点(192.168.0.1)构成的, 而在struct in_addr结构中用的是32位的IP, 我们上面那个32位IP(C0A80001)是的192.168.0.1 为了转换我们可以使用下面两个函数int inet_aton(const char *cp,struct in_addr *inp)char *inet_ntoa(struct in_addr in)函数里面a 代表ascii n 代表network.第一个函数表示将a.b.c.d的IP转换为32位的IP,存储在inp指针里面.第二个是将32位IP转换为a.b.c.d的格式.3.4 服务信息函数在网络程序里面我们有时候需要知道端口.IP和服务信息.这个时候我们可以使用以下几个函数int getsockname(int sockfd,struct sockaddr *localaddr,int *addrlen)int getpeername(int sockfd,struct sockaddr *peeraddr, int *addrlen)struct servent *getservbyname(const char *servname,const char *protoname) struct servent *getservbyport(int port,const char *protoname)struct servent{char *s_name; /* 正式服务名*/char **s_aliases; /* 别名列表*/int s_port; /* 端口号*/char *s_proto; /* 使用的协议*/}一般我们很少用这几个函数.对应客户端,当我们要得到连接的端口号时在connect调用成功后使用可得到系统分配的端口号.对于服务端,我们用INADDR_ANY填充后,为了得到连接的IP我们可以在accept调用成功后使用而得到IP地址.在网络上有许多的默认端口和服务,比如端口21对ftp80对应WWW.为了得到指定的端口号的服务我们可以调用第四个函数,相反为了得到端口号可以调用第三个函数.3.5 一个例子#include <netdb.h>;#include <stdio.h>;#include <stdlib.h>;#include <sys/socket.h>;#include <netinet/in.h>;int main(int argc ,char **argv){struct sockaddr_in addr;struct hostent *host;char **alias;if(argc<2){fprintf(stderr,"Usage:%s hostname|ip..\n\a",argv[0]); exit(1);}argv++;for(;*argv!=NULL;argv++){/* 这里我们假设是IP*/if(inet_aton(*argv,&addr.sin_addr)!=0){host=gethostbyaddr((char *)&addr.sin_addr,4,AF_INET); printf("Address information of Ip %s\n",*argv);}else{/* 失败,难道是域名?*/host=gethostbyname(*argv); printf("Address information of host %s\n",*argv);}if(host==NULL){/* 都不是,算了不找了*/fprintf(stderr,"No address information of %s\n",*argv); continue;}printf("Official host name %s\n",host->;h_name);printf("Name aliases:");for(alias=host->;h_aliases;*alias!=NULL;alias++)printf("%s ,",*alias);printf("\nIp address:");for(alias=host->;h_addr_list;*alias!=NULL;alias++)printf("%s ,",inet_ntoa(*(struct in_addr *)(*alias)));}}在这个例子里面,为了判断用户输入的是IP还是域名我们调用了两个函数,第一次我们假设输入的是IP所以调用inet_aton, 失败的时候,再调用gethostbyname而得到信息.4. 完整的读写函数一旦我们建立了连接,我们的下一步就是进行通信了.在unix下面把我们前面建立的通道看成是文件描述符,这样服务器端和客户端进行通信时候,只要往文件描述符里面读写东西了. 就象我们往文件读写一样.4.1 写函数writessize_t write(int fd,const void *buf,size_t nbytes)write函数将buf中的nbytes字节内容写入文件描述符fd.成功时返回写的字节数.失败时返回-1. 并设置errno变量. 在网络程序中,当我们向套接字文件描述符写时有俩种可能.1)write的返回值大于0,表示写了部分或者是全部的数据.2)返回的值小于0,此时出现了错误.我们要根据错误类型来处理.如果错误为EINTR表示在写的时候出现了中断错误.如果为EPIPE表示网络连接出现了问题(对方已经关闭了连接).为了处理以上的情况,我们自己编写一个写函数来处理这几种情况.int my_write(int fd,void *buffer,int length){int bytes_left;int written_bytes;char *ptr;ptr=buffer;bytes_left=length;while(bytes_left>;0){/* 开始写*/written_bytes=write(fd,ptr,bytes_left);if(written_bytes<=0) /* 出错了*/{if(errno==EINTR) /* 中断错误我们继续写*/written_bytes=0;else /* 其他错误没有办法,只好撤退了*/return(-1);}bytes_left-=written_bytes;ptr+=written_bytes; /* 从剩下的地方继续写*/}return(0);}4.2 读函数readssize_t read(int fd,void *buf,size_t nbyte) read函数是负责从fd中读取内容.当读成功时,read返回实际所读的字节数,如果返回的值是0 表示已经读到文件的结束了,小于0表示出现了错误.如果错误为EINTR说明读是由中断引起的, 如果是ECONNREST表示网络连接出了问题. 和上面一样,我们也写一个自己的读函数.int my_read(int fd,void *buffer,int length) {int bytes_left;int bytes_read;char *ptr;bytes_left=length;while(bytes_left>;0){bytes_read=read(fd,ptr,bytes_read);if(bytes_read<0){if(errno==EINTR)bytes_read=0;elsereturn(-1);}else if(bytes_read==0)break;bytes_left-=bytes_read;ptr+=bytes_read;}return(length-bytes_left);}4.3 数据的传递有了上面的两个函数,我们就可以向客户端或者是服务端传递数据了.比如我们要传递一个结构.可以使用如下方式/* 客户端向服务端写*/struct my_struct my_struct_client;write(fd,(void *)&my_struct_client,sizeof(struct my_struct);/* 服务端的读*/char buffer[sizeof(struct my_struct)];struct *my_struct_server;read(fd,(void *)buffer,sizeof(struct my_struct));my_struct_server=(struct my_struct *)buffer;在网络上传递数据时我们一般都是把数据转化为char类型的数据传递.接收的时候也是一样的注意的是我们没有必要在网络上传递指针(因为传递指针是没有任何意义的,我们必须传递指针所指向的内容)5. 用户数据报发送我们前面已经学习网络程序的一个很大的部分,由这个部分的知识,我们实际上可以写出大部分的基于TCP协议的网络程序了.现在在unix下的大部分程序都是用我们上面所学的知识来写的.我们可以去找一些源程序来参考一下.这一章,我们简单的学习一下基于UDP协议的网络程序.5.1 两个常用的函数int recvfrom(int sockfd,void *buf,int len,unsigned int flags,struct sockaddr * from int *fromlen)int sendto(int sockfd,const void *msg,int len,unsigned int flags,struct sockaddr *to int tolen)sockfd,buf,len的意义和read,write一样,分别表示套接字描述符,发送或接收的缓冲区及大小.recvfrom负责从sockfd接收数据,如果from不是NULL,那么在from里面存储了信息来源的情况,如果对信息的来源不感兴趣,可以将from和fromlen设置为NULL.sendto负责向to发送信息.此时在to里面存储了收信息方的详细资料.5.2 一个实例/* 服务端程序server.c */#include <sys/types.h>;#include <sys/socket.h>;#include <netinet/in.h>;#include <stdio.h>;#include <errno.h>;#define SERVER_PORT 8888#define MAX_MSG_SIZE 1024void udps_respon(int sockfd){struct sockaddr_in addr;int addrlen,n;char msg[MAX_MSG_SIZE];while(1){ /* 从网络上度,写到网络上面去*/n=recvfrom(sockfd,msg,MAX_MSG_SIZE,0, (struct sockaddr*)&addr,&addrlen);msg[n]=0;/* 显示服务端已经收到了信息*/fprintf(stdout,"I have received %s",msg);sendto(sockfd,msg,n,0,(struct sockaddr*)&addr,addrlen);}}int main(void){int sockfd;struct sockaddr_in addr;sockfd=socket(AF_INET,SOCK_DGRAM,0);if(sockfd<0){fprintf(stderr,"Socket Error:%s\n",strerror(errno));exit(1);}bzero(&addr,sizeof(struct sockaddr_in));addr.sin_family=AF_INET;addr.sin_addr.s_addr=htonl(INADDR_ANY);addr.sin_port=htons(SERVER_PORT);if(bind(sockfd,(struct sockaddr *)&ddr,sizeof(struct sockaddr_in))<0) {fprintf(stderr,"Bind Error:%s\n",strerror(errno));exit(1);}udps_respon(sockfd);close(sockfd);}/* 客户端程序*/#include <sys/types.h>;#include <sys/socket.h>;#include <netinet/in.h>;#include <errno.h>;#include <stdio.h>;#include <unistd.h>;#define MAX_BUF_SIZE 1024void udpc_requ(int sockfd,const struct sockaddr_in *addr,int len) {char buffer[MAX_BUF_SIZE];int n;while(1){ /* 从键盘读入,写到服务端*/fgets(buffer,MAX_BUF_SIZE,stdin);sendto(sockfd,buffer,strlen(buffer),0,addr,len);bzero(buffer,MAX_BUF_SIZE);/* 从网络上读,写到屏幕上*/n=recvfrom(sockfd,buffer,MAX_BUF_SIZE,0,NULL,NULL); buffer[n]=0;fputs(buffer,stdout);}}int main(int argc,char **argv){int sockfd,port;struct sockaddr_in addr;if(argc!=3){fprintf(stderr,"Usage:%s server_ip server_port\n",argv[0]); exit(1);}if((port=atoi(argv[2]))<0){fprintf(stderr,"Usage:%s server_ip server_port\n",argv[0]); exit(1);}sockfd=socket(AF_INET,SOCK_DGRAM,0);if(sockfd<0){fprintf(stderr,"Socket Error:%s\n",strerror(errno));exit(1);}/* 填充服务端的资料*/bzero(&addr,sizeof(struct sockaddr_in));addr.sin_family=AF_INET;addr.sin_port=htons(port);if(inet_aton(argv[1],&addr.sin_addr)<0){fprintf(stderr,"Ip error:%s\n",strerror(errno));exit(1);}udpc_requ(sockfd,&addr,sizeof(struct sockaddr_in)); close(sockfd);}########### 编译文件Makefile ##########all:server clientserver:server.cgcc -o server server.cclient:client.cgcc -o client client.cclean:rm -f serverrm -f clientrm -f core上面的实例如果大家编译运行的话,会发现一个小问题的. 在我机器上面,我先运行服务端,然后运行客户端.在客户端输入信息,发送到服务端, 在服务端显示已经收到信息,但是客户端没有反映.再运行一个客户端,向服务端发出信息却可以得到反应.我想可能是第一个客户端已经阻塞了.如果谁知道怎么解决的话,请告诉我,谢谢. 由于UDP协议是不保证可靠接收数据的要求,所以我们在发送信息的时候,系统并不能够保证我们发出的信息都正确无误的到达目的地.一般的来说我们在编写网络程序的时候都是选用TCP协议的.6. 高级套接字函数在前面的几个部分里面,我们已经学会了怎么样从网络上读写信息了.前面的一些函数(read,write)是网络程序里面最基本的函数.也是最原始的通信函数.在这一章里面,我们一起来学习网络通信的高级函数.这一章我们学习另外几个读写函数.6.1 recv和sendrecv和send函数提供了和read和write差不多的功能.不过它们提供了第四个参数来控制读写操作.int recv(int sockfd,void *buf,int len,int flags)int send(int sockfd,void *buf,int len,int flags)前面的三个参数和read,write一样,第四个参数可以是0或者是以下的组合_______________________________________________________________| MSG_DONTROUTE | 不查找路由表|| MSG_OOB | 接受或者发送带外数据|| MSG_PEEK | 查看数据,并不从系统缓冲区移走数据|| MSG_WAITALL | 等待所有数据||---------------------------------------------------------------|MSG_DONTROUTE:是send函数使用的标志.这个标志告诉IP协议.目的主机在本地网络上面,没有必要查找路由表.这个标志一般用网络诊断和路由程序里面.MSG_OOB:表示可以接收和发送带外的数据.关于带外数据我们以后会解释的.MSG_PEEK:是recv函数的使用标志,表示只是从系统缓冲区中读取内容,而不清楚系统缓冲区的内容.这样下次读的时候,仍然是一样的内容.一般在有多个进程读写数据时可以使用这个标志.MSG_WAITALL是recv函数的使用标志,表示等到所有的信息到达时才返回.使用这个标志的时候recv回一直阻塞,直到指定的条件满足,或者是发生了错误. 1)当读到了指定的字节时,函数正常返回.返回值等于len 2)当读到了文件的结尾时,函数正常返回.返回值小于len 3)当操作发生错误时,返回-1,且设置错误为相应的错误号(errno)如果flags为0,则和read,write一样的操作.还有其它的几个选项,不过我们实际上用的很少,可以查看unix Programmer's Manual得到详细解释.6.2 recvfrom和sendto这两个函数一般用在非套接字的网络程序当中(UDP),我们已经在前面学会了.6.3 recvmsg和sendmsgrecvmsg和sendmsg可以实现前面所有的读写函数的功能.int recvmsg(int sockfd,struct msghdr *msg,int flags)int sendmsg(int sockfd,struct msghdr *msg,int flags)struct msghdr{void *msg_name;int msg_namelen;struct iovec *msg_iov;int msg_iovlen;void *msg_control;int msg_controllen;int msg_flags;}struct iovec{void *iov_base; /* 缓冲区开始的地址*/size_t iov_len; /* 缓冲区的长度*/}msg_name和msg_namelen当套接字是非面向连接时(UDP),它们存储接收和发送方的地址信息.msg_name实际上是一个指向struct sockaddr的指针,msg_name是结构的长度.当套接字是面向连接时,这两个值应设为NULL. msg_iov和msg_iovlen指出接受和发送的缓冲区内容.msg_iov是一个结构指针,msg_iovlen指出这个结构数组的大小. msg_control 和msg_controllen这两个变量是用来接收和发送控制数据时的msg_flags指定接受和发送的操作选项.和recv,send的选项一样6.4 套接字的关闭关闭套接字有两个函数close和shutdown.用close时和我们关闭文件一样.6.5 shutdownint shutdown(int sockfd,int howto)TCP连接是双向的(是可读写的),当我们使用close时,会把读写通道都关闭,有时侯我们希望只关闭一个方向,这个时候我们可以使用shutdown.针对不同的howto,系统回采取不同的关闭方式.howto=0这个时候系统会关闭读通道.但是可以继续往接字描述符写.howto=1关闭写通道,和上面相反,着时候就只可以读了.howto=2关闭读写通道,和close一样在多进程程序里面,如果有几个子进程共享一个套接字时,如果我们使用shutdown, 那么所有的子进程都不能够操作了,这个时候我们只能够使用close来关闭子进程的套接字描述符.7. TCP/IP协议你也许听说过TCP/IP协议,那么你知道到底什么是TCP,什么是IP吗?在这一章里面,我们一起来学习这个目前网络上用最广泛的协议.7.1 网络传输分层如果你考过计算机等级考试,那么你就应该已经知道了网络传输分层这个概念.在网络上,人们为了传输数据时的方便,把网络的传输分为7个层次.分别是:应用层,表示层,会话层,传输层,网络层,数据链路层和物理层.分好了层以后,传输数据时,上一层如果要数据的话,就可以直接向下一层要了,而不必要管数据传输的细节.下一层也只向它的上一层提供数据,而不要去管其它东西了.如果你不想考试,你没有必要去记这些东西的.只要知道是分层的,而且各层的作用不同.7.2 IP协议IP协议是在网络层的协议.它主要完成数据包的发送作用. 下面这个表是IP4的数据包格式0 4 8 16 32--------------------------------------------------|版本|首部长度|服务类型| 数据包总长|--------------------------------------------------| 标识|DF |MF| 碎片偏移|--------------------------------------------------| 生存时间| 协议| 首部较验和|------------------------------------------------| 源IP地址|------------------------------------------------| 目的IP地址|-------------------------------------------------| 选项|================================================= | 数据|-------------------------------------------------下面我们看一看IP的结构定义<netinet/ip.h>;struct ip{#if __BYTE_ORDER == __LITTLE_ENDIANunsigned int ip_hl:4; /* header length */unsigned int ip_v:4; /* version */#endif#if __BYTE_ORDER == __BIG_ENDIANunsigned int ip_v:4; /* version */unsigned int ip_hl:4; /* header length */#endifu_int8_t ip_tos; /* type of service */u_short ip_len; /* total length */u_short ip_id; /* identification */u_short ip_off; /* fragment offset field */#define IP_RF 0x8000 /* reserved fragment flag */#define IP_DF 0x4000 /* dont fragment flag */#define IP_MF 0x2000 /* more fragments flag */#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */u_int8_t ip_ttl; /* time to live */u_int8_t ip_p; /* protocol */u_short ip_sum; /* checksum */struct in_addr ip_src, ip_dst; /* source and dest address */};ip_vIP协议的版本号,这里是4,现在IPV6已经出来了ip_hlIP包首部长度,这个值以4字节为单位.IP协议首部的固定长度为20个字节,如果IP包没有选项,那么这个值为5.ip_tos服务类型,说明提供的优先权.ip_len说明IP数据的长度.以字节为单位.ip_id标识这个IP数据包.ip_off碎片偏移,这和上面ID一起用来重组碎片的.ip_ttl生存时间.没经过一个路由的时候减一,直到为0时被抛弃.ip_p协议,表示创建这个IP数据包的高层协议.如TCP,UDP协议.ip_sum首部校验和,提供对首部数据的校验.ip_src,ip_dst发送者和接收者的IP地址关于IP协议的详细情况,请参考RFC7917.3 ICMP协议ICMP是消息控制协议,也处于网络层.在网络上传递IP数据包时,如果发生了错误,那么就会用ICMP协议来报告错误.ICMP包的结构如下:0 8 16 32---------------------------------------------------------------------| 类型| 代码| 校验和|--------------------------------------------------------------------| 数据| 数据|--------------------------------------------------------------------ICMP在<netinet/ip_icmp.h>;中的定义是struct icmphdr{u_int8_t type; /* message type */u_int8_t code; /* type sub-code */u_int16_t checksum;union{struct{u_int16_t id;u_int16_t sequence;} echo; /* echo datagram */u_int32_t gateway; /* gateway address */struct{u_int16_t __unused;u_int16_t mtu;} frag; /* path mtu discovery */} un;};关于ICMP协议的详细情况可以查看RFC7927.4 UDP协议UDP协议是建立在IP协议基础之上的,用在传输层的协议.UDP和IP协议一样是不可靠的数据报服务.UDP的头格式为:0 16 32---------------------------------------------------| UDP源端口| UDP目的端口|---------------------------------------------------| UDP数据报长度| UDP数据报校验|---------------------------------------------------UDP结构在<netinet/udp.h>;中的定义为:struct udphdr {u_int16_t source;u_int16_t dest;u_int16_t len;u_int16_t check;};关于UDP协议的详细情况,请参考RFC7687.5 TCPTCP协议也是建立在IP协议之上的,不过TCP协议是可靠的.按照顺序发送的.TCP的数据结构比前面的结构都要复杂.0 4 8 10 16 24 32-------------------------------------------------------------------| 源端口| 目的端口|-------------------------------------------------------------------| 序列号|------------------------------------------------------------------| 确认号|------------------------------------------------------------------| | |U|A|P|S|F| ||首部长度| 保留|R|C|S|Y|I| 窗口|| | |G|K|H|N|N| |-----------------------------------------------------------------| 校验和| 紧急指针|-----------------------------------------------------------------| 选项| 填充字节|-----------------------------------------------------------------TCP的结构在<netinet/tcp.h>;中定义为:struct tcphdr{u_int16_t source;u_int16_t dest;u_int32_t seq;u_int32_t ack_seq;#if __BYTE_ORDER == __LITTLE_ENDIANu_int16_t res1:4;u_int16_t doff:4;u_int16_t fin:1;u_int16_t syn:1;u_int16_t rst:1;u_int16_t psh:1;u_int16_t ack:1;u_int16_t urg:1;u_int16_t res2:2;#elif __BYTE_ORDER == __BIG_ENDIANu_int16_t doff:4;u_int16_t res1:4;u_int16_t res2:2;u_int16_t urg:1;u_int16_t ack:1;u_int16_t psh:1;u_int16_t rst:1;u_int16_t syn:1;u_int16_t fin:1;#endifu_int16_t window;u_int16_t check;u_int16_t urg_prt;};source发送TCP数据的源端口dest接受TCP数据的目的端口seq标识该TCP所包含的数据字节的开始序列号ack_seq确认序列号,表示接受方下一次接受的数据序列号.doff数据首部长度.和IP协议一样,以4字节为单位.一般的时候为5urg如果设置紧急数据指针,则该位为1ack如果确认号正确,那么为1psh如果设置为1,那么接收方收到数据后,立即交给上一层程序rst为1的时候,表示请求重新连接syn为1的时候,表示请求建立连接fin为1的时候,表示亲戚关闭连接window窗口,告诉接收者可以接收的大小check对TCP数据进行较核urg_ptr如果urg=1,那么指出紧急数据对于历史数据开始的序列号的偏移值关于TCP协议的详细情况,请查看RFC7937.6 TCP连接的建立TCP协议是一种可靠的连接,为了保证连接的可靠性,TCP的连接要分为几个步骤.我们把这个连接过程称为"三次握手".下面我们从一个实例来分析建立连接的过程.第一步客户机向服务器发送一个TCP数据包,表示请求建立连接. 为此,客户端将数据包的SYN位设置为1,并且设置序列号seq=1000(我们假设为1000).第二步服务器收到了数据包,并从SYN位为1知道这是一个建立请求的连接.于是服务器也向客户端发送一个TCP数据包.因为是响应客户机的请求,于是服务器设置ACK为1,sak_seq=1001(1000+1)同时设置自己的序列号.seq=2000(我们假设为2000).第三步客户机收到了服务器的TCP,并从ACK为1和ack_seq=1001知道是从服务器来的确认信息.于是客户机也向服务器发送确认信息.客户机设置ACK=1,和ack_seq=2001,seq=1001,发送给服务器.至此客户端完成连接.最后一步服务器受到确认信息,也完成连接.通过上面几个步骤,一个TCP连接就建立了.当然在建立过程中可能出现错误,不过TCP协议可以保证自己去处理错误的.说一说其中的一种错误.听说过DOS吗?(可不是操作系统啊).今年春节的时候,美国的五大网站一起受到攻击.攻击者用的就是DOS(拒绝式服务)方式.概括的说一下原理.客户机先进行第一个步骤.服务器收到后,进行第二个步骤.按照正常的TCP连接,客户机应该进行第三个步骤.不过攻击者实际上并不进行第三个步骤.因为客户端在进行第一个步骤的时候,修改了自己的IP地址,就是说将一个实际上不存在的IP填充在自己IP数据包的发送者的IP一栏.这样因为服务器发的IP地址没有人接收,所以服务端会收不到第三个步骤的确认信号,这样服务务端会在那边一直等待,直到超时.这样当有大量的客户发出请求后,服务端会有大量等待,直到所有的资源被用光,而不能再接收客户机的请求.这样当正常的用户向服务器发出请求时,由于没有了资源而不能成功.于是就出现了春节时所出现的情况.8. 套接字选项有时候我们要控制套接字的行为(如修改缓冲区的大小),这个时候我们就要控制套接字的选项了.8.1 getsockopt和setsockopt。
《UNIX网络编程》之read_timeout实验
《UNIX⽹络编程》之read_timeout实验最近在做项⽬,需要做⼀个服务器和客户端的基于TCP的套接⼝⽹络编程,由于服务器端返回数据并不是那么的及时,因此,需要在客户端做些延迟,然后才能去读取数据,实验测试结果如下。
⾸先,我们先来看⼀下我们封装好的⼀个读延时函数:#define ERR_EXIT(m) \do \{ \perror(m); \exit(EXIT_FAILURE); \}while(0)/*** read timeout - 读超时检测函数,不含读操作* @fd: ⽂件描述符* @wait_seconds: 等待超时秒数,如果为0标识不检测超时* 成功(未超时)返回0,失败返回-1,超时返回-1并且errno = ETIMEOUT*/int read_timeout(int fd, unsigned int wait_seconds){int ret;if(wait_seconds > 0){fd_set read_fdset;struct timeval timeout;FD_ZERO(&read_fdset);FD_SET(fd, &read_fdset);_sec = wait_seconds;_usec = 0;do{ret = select(fd + 1, &read_fdset, NULL, NULL, &timeout);}while(ret < 0 && errno == EINTR);if(ret == 0)//fail{//time out.ret = -1;errno = ETIMEDOUT;}else if(ret == 1)//success{ret = 0;}}return ret;}下⾯,我们介绍如何使⽤该函数,伪代码如下:int ret = read_timeout(sockfd, 15);if(ret == 0){ readnum = read(sockfd, recvbuff, sizeof(recvbuff));}else if(ret == -1 && errno == ETIMEDOUT){//time out dealing.}好,现在继续看我的服务器与客户端程序:服务器void str_echo(int sock){ssize_t n;char buff[1024];again:while( (n = read(sock, buff, sizeof(buff))) > 0){fputs(buff, stdout);sleep(3);//for testing client read_timeoutwrite(sock, buff, n);}if(n < 0 && errno == EINTR){goto again;else if(n < 0){ERR_EXIT("read");}}int main(){int listenfd, connfd;pid_t childpid;socklen_t clilen;struct sockaddr_in servaddr, cliaddr;if( (listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){ERR_EXIT("socket");}memset(&servaddr, 0, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_addr.s_addr = htonl(INADDR_ANY);servaddr.sin_port = htons(5188);if((bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr))) < 0) {ERR_EXIT("bind");}if( (listen(listenfd, SOMAXCONN)) < 0){ERR_EXIT("listen");}for(;;){clilen = sizeof(cliaddr);connfd = accept(listenfd, (struct sockaddr*)&cliaddr, &clilen);if(connfd < 0){ERR_EXIT("connect");}if( (childpid = fork()) == 0){//childclose(listenfd);str_echo(connfd);exit(0);}else{//parentclose(connfd);}}}客户端void str_cli(int sock){char sendbuff[1024];char recvbuff[1024];memset(sendbuff, 0, sizeof(sendbuff));memset(recvbuff, 0, sizeof(recvbuff));int ret = -1;//ssize_t n;while(fgets(sendbuff, sizeof(sendbuff), stdin) != NULL){write(sock, sendbuff, strlen(sendbuff));ret = read_timeout(sock, 15);if(ret == 0){read(sock, recvbuff, sizeof(recvbuff));}else if(ret == -1 && errno == ETIMEDOUT)ERR_EXIT("read_timeout");}fputs(recvbuff, stdout);}}int main(int argc, char **argv){int sockfd;struct sockaddr_in servaddr;memset(&servaddr, 0, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");servaddr.sin_port = htons(5188);sockfd = socket(AF_INET, SOCK_STREAM, 0);if(sockfd < 0){ERR_EXIT("socket");}if( (connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr))) < 0) {ERR_EXIT("connect");}str_cli(sockfd);return0;}例⼦⼀:服务器延时3s, 客户端read_timeout(socd, 5);结果为:成功。
《Unix网络编程》第一卷第三版unp.h
/* include unph *//* Our own header. Tabs are set for 4 spaces, not 8 */#ifndef__unp_h#define__unp_h#include"../config.h"/* configuration options for current OS *//* "../config.h" is generated by configure */ /* If anything changes in the following list of #includes, must change acsite.m4 also, for configure's tests. */#include<sys/types.h>/* basic system data types */#include<sys/socket.h>/* basic socket definitions */#if TIME_WITH_SYS_TIME#include<sys/time.h>/* timeval{} for select() */#include<time.h>/* timespec{} for pselect() */#else#if HAVE_SYS_TIME_H#include<sys/time.h>/* includes <time.h> unsafely */#else#include<time.h>/* old system? */#endif#endif#include<netinet/in.h>/* sockaddr_in{} and other Internet defns */#include<arpa/inet.h>/* inet(3) functions */#include<errno.h>#include<fcntl.h>/* for nonblocking */#include<netdb.h>#include<signal.h>#include<stdio.h>#include<stdlib.h>#include<string.h>#include<sys/stat.h>/* for S_xxx file mode constants */#include<sys/uio.h>/* for iovec{} and readv/writev */#include<unistd.h>#include<sys/wait.h>#include<sys/un.h>/* for Unix domain sockets */#ifdef HAVE_SYS_SELECT_H# include<sys/select.h>/* for convenience */#endif#ifdef HAVE_SYS_SYSCTL_H#ifdef HAVE_SYS_PARAM_H# include<sys/param.h>/* OpenBSD prereq for sysctl.h */#endif# include<sys/sysctl.h>#endif#ifdef HAVE_POLL_H# include<poll.h>/* for convenience */#endif#ifdef HAVE_SYS_EVENT_H# include<sys/event.h>/* for kqueue */#endif#ifdef HAVE_STRINGS_H# include<strings.h>/* for convenience */#endif/* Three headers are normally needed for socket/file ioctl's:* <sys/ioctl.h>, <sys/filio.h>, and <sys/sockio.h>.*/#ifdef HAVE_SYS_IOCTL_H# include<sys/ioctl.h>#endif#ifdef HAVE_SYS_FILIO_H# include<sys/filio.h>#endif#ifdef HAVE_SYS_SOCKIO_H# include<sys/sockio.h>#endif#ifdef HAVE_PTHREAD_H# include<pthread.h>#endif#ifdef HAVE_NET_IF_DL_H# include<net/if_dl.h>#endif#ifdef HAVE_NETINET_SCTP_H#include<netinet/sctp.h>#endif/* OSF/1 actually disables recv() and send() in <sys/socket.h> */ #ifdef__osf__#undef recv#undef send#define recv(a,b,c,d) recvfrom(a,b,c,d,0,0)#define send(a,b,c,d) sendto(a,b,c,d,0,0)#endif#ifndef INADDR_NONE/* $$.Ic INADDR_NONE$$ */#define INADDR_NONE0xffffffff /* should have been in <netinet/in.h> */ #endif#ifndef SHUT_RD/* these three POSIX names are new */#define SHUT_RD0 /* shutdown for reading */#define SHUT_WR 1 /* shutdown for writing */#define SHUT_RDWR 2 /* shutdown for reading and writing *//* $$.Ic SHUT_RD$$ *//* $$.Ic SHUT_WR$$ *//* $$.Ic SHUT_RDWR$$ */#endif/* *INDENT-OFF* */#ifndef INET_ADDRSTRLEN/* $$.Ic INET_ADDRSTRLEN$$ */#define INET_ADDRSTRLEN16 /* "ddd.ddd.ddd.ddd\0"1234567890123456 */#endif/* Define following even if IPv6 not supported, so we can always allocate an adequately sized buffer without #ifdefs in the code. */#ifndef INET6_ADDRSTRLEN/* $$.Ic INET6_ADDRSTRLEN$$ */#define INET6_ADDRSTRLEN46 /* max size of IPv6 address string:"xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx" or"xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:ddd.ddd.ddd.ddd\0"1234567890123456789012345678901234567890123456 */ #endif/* *INDENT-ON* *//* Define bzero() as a macro if it's not in standard C library. */#ifndef HAVE_BZERO#define bzero(ptr,n) memset(ptr, 0, n)/* $$.If bzero$$ *//* $$.If memset$$ */#endif/* Older resolvers do not have gethostbyname2() */#ifndef HAVE_GETHOSTBYNAME2#define gethostbyname2(host,family) gethostbyname((host))#endif/* The structure returned by recvfrom_flags() */struct unp_in_pktinfo {struct in_addr ipi_addr; /* dst IPv4 address */int ipi_ifindex;/* received interface index */};/* $$.It unp_in_pktinfo$$ *//* $$.Ib ipi_addr$$ *//* $$.Ib ipi_ifindex$$ *//* We need the newer CMSG_LEN() and CMSG_SPACE() macros, but few implementations support them today. These two macros really needan ALIGN() macro, but each implementation does this differently. */#ifndef CMSG_LEN/* $$.Im CMSG_LEN$$ */#define CMSG_LEN(size) (sizeof(struct cmsghdr) + (size))#endif#ifndef CMSG_SPACE/* $$.Im CMSG_SPACE$$ */#define CMSG_SPACE(size) (sizeof(struct cmsghdr) + (size))#endif/* POSIX requires the SUN_LEN() macro, but not all implementations DefinE it (yet). Note that this 4.4BSD macro works regardless whether there isa length field or not. */#ifndef SUN_LEN/* $$.Im SUN_LEN$$ */# define SUN_LEN(su) \(sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))#endif/* POSIX renames "Unix domain" as "local IPC."Not all systems DefinE AF_LOCAL and PF_LOCAL (yet). */#ifndef AF_LOCAL#define AF_LOCAL AF_UNIX#endif#ifndef PF_LOCAL#define PF_LOCAL PF_UNIX#endif/* POSIX requires that an #include of <poll.h> DefinE INFTIM, but many systems still DefinE it in <sys/stropts.h>. We don't want to includeall the STREAMS stuff if it's not needed, so we just DefinE INFTIM here.This is the standard value, but there's no guarantee it is -1. */#ifndef INFTIM#define INFTIM(-1) /* infinite poll timeout *//* $$.Ic INFTIM$$ */#ifdef HAVE_POLL_H#define INFTIM_UNPH/* tell unpxti.h we defined it */#endif#endif/* Following could be derived from SOMAXCONN in <sys/socket.h>, but many kernels still #define it as 5, while actually supporting many more */#define LISTENQ1024 /* 2nd argument to listen() *//* Miscellaneous constants */#define MAXLINE4096 /* max text line length */#define BUFFSIZE8192 /* buffer size for reads and writes *//* Define some port number that can be used for our examples */#define SERV_PORT9877 /* TCP and UDP */#define SERV_PORT_STR"9877"/* TCP and UDP */#define UNIXSTR_PATH"/tmp/unix.str"/* Unix domain stream */#define UNIXDG_PATH"/tmp/unix.dg"/* Unix domain datagram *//* $$.ix [LISTENQ]~constant,~definition~of$$ *//* $$.ix [MAXLINE]~constant,~definition~of$$ *//* $$.ix [BUFFSIZE]~constant,~definition~of$$ *//* $$.ix [SERV_PORT]~constant,~definition~of$$ *//* $$.ix [UNIXSTR_PATH]~constant,~definition~of$$ *//* $$.ix [UNIXDG_PATH]~constant,~definition~of$$ *//* Following shortens all the typecasts of pointer arguments: */#define SA struct sockaddr#ifndef HAVE_STRUCT_SOCKADDR_STORAGE/** RFC 3493: protocol-independent placeholder for socket addresses*/#define__SS_MAXSIZE128#define__SS_ALIGNSIZE(sizeof(int64_t))#ifdef HAVE_SOCKADDR_SA_LEN#define__SS_PAD1SIZE(__SS_ALIGNSIZE - sizeof(u_char) - sizeof(sa_family_t)) #else#define__SS_PAD1SIZE(__SS_ALIGNSIZE - sizeof(sa_family_t))#endif#define__SS_PAD2SIZE(__SS_MAXSIZE - 2*__SS_ALIGNSIZE)struct sockaddr_storage {#ifdef HAVE_SOCKADDR_SA_LENu_char ss_len;#endifsa_family_t ss_family;char__ss_pad1[__SS_PAD1SIZE];int64_t__ss_align;char__ss_pad2[__SS_PAD2SIZE];};#endif#define FILE_MODE(S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)/* default file access permissions for new files */#define DIR_MODE(FILE_MODE | S_IXUSR | S_IXGRP | S_IXOTH)/* default permissions for new directories */ typedef void Sigfunc(int); /* for signal handlers */#define min(a,b) ((a) < (b) ? (a) : (b))#define max(a,b) ((a) > (b) ? (a) : (b))#ifndef HAVE_ADDRINFO_STRUCT# include"../lib/addrinfo.h"#endif#ifndef HAVE_IF_NAMEINDEX_STRUCTstruct if_nameindex {unsigned int if_index; /* 1, 2, ... */char*if_name; /* null-terminated name: "le0", ... */ };/* $$.It if_nameindex$$ *//* $$.Ib if_index$$ *//* $$.Ib if_name$$ */#endif#ifndef HAVE_TIMESPEC_STRUCTstruct timespec {time_t tv_sec; /* seconds */long tv_nsec; /* and nanoseconds */};/* $$.It timespec$$ *//* $$.Ib tv_sec$$ *//* $$.Ib tv_nsec$$ */#endif/* end unph *//* prototypes for our own library functions */int connect_nonb(int, const SA *, socklen_t, int);int connect_timeo(int, const SA *, socklen_t, int);int daemon_init(const char *, int);void daemon_inetd(const char *, int);void dg_cli(FILE *, int, const SA *, socklen_t);void dg_echo(int, SA *, socklen_t);int family_to_level(int);char*gf_time(void);void heartbeat_cli(int, int, int);void heartbeat_serv(int, int, int);struct addrinfo *host_serv(const char *, const char *, int, int);int inet_srcrt_add(char *);u_char*inet_srcrt_init(int);void inet_srcrt_print(u_char *, int);void inet6_srcrt_print(void *);char**my_addrs(int *);int readable_timeo(int, int);ssize_t readline(int, void *, size_t);ssize_t readn(int, void *, size_t);ssize_t read_fd(int, void *, size_t, int *);ssize_t recvfrom_flags(int, void *, size_t, int *, SA *, socklen_t *,struct unp_in_pktinfo *);Sigfunc *signal_intr(int, Sigfunc *);int sock_bind_wild(int, int);int sock_cmp_addr(const SA *, const SA *, socklen_t);int sock_cmp_port(const SA *, const SA *, socklen_t);int sock_get_port(const SA *, socklen_t);void sock_set_addr(SA *, socklen_t, const void *);void sock_set_port(SA *, socklen_t, int);void sock_set_wild(SA *, socklen_t);char*sock_ntop(const SA *, socklen_t);char*sock_ntop_host(const SA *, socklen_t);int sockfd_to_family(int);void str_echo(int);void str_cli(FILE *, int);int tcp_connect(const char *, const char *);int tcp_listen(const char *, const char *, socklen_t *);void tv_sub(struct timeval *, struct timeval *);int udp_client(const char *, const char *, SA **, socklen_t *);int udp_connect(const char *, const char *);int udp_server(const char *, const char *, socklen_t *);int writable_timeo(int, int);ssize_t writen(int, const void *, size_t);ssize_t write_fd(int, void *, size_t, int);#ifdef MCASTint mcast_leave(int, const SA *, socklen_t);int mcast_join(int, const SA *, socklen_t, const char *, u_int);int mcast_leave_source_group(int sockfd, const SA *src, socklen_t srclen,const SA *grp, socklen_t grplen);int mcast_join_source_group(int sockfd, const SA *src, socklen_t srclen,const SA *grp, socklen_t grplen,const char *ifname, u_int ifindex);int mcast_block_source(int sockfd, const SA *src, socklen_t srclen,const SA *grp, socklen_t grplen);int mcast_unblock_source(int sockfd, const SA *src, socklen_t srclen,const SA *grp, socklen_t grplen);int mcast_get_if(int);int mcast_get_loop(int);int mcast_get_ttl(int);int mcast_set_if(int, const char *, u_int);int mcast_set_loop(int, int);int mcast_set_ttl(int, int);void Mcast_leave(int, const SA *, socklen_t);void Mcast_join(int, const SA *, socklen_t, const char *, u_int);void Mcast_leave_source_group(int sockfd, const SA *src, socklen_t srclen,const SA *grp, socklen_t grplen);void Mcast_join_source_group(int sockfd, const SA *src, socklen_t srclen,const SA *grp, socklen_t grplen,const char *ifname, u_int ifindex);void Mcast_block_source(int sockfd, const SA *src, socklen_t srclen,const SA *grp, socklen_t grplen);void Mcast_unblock_source(int sockfd, const SA *src, socklen_t srclen,const SA *grp, socklen_t grplen);int Mcast_get_if(int);int Mcast_get_loop(int);int Mcast_get_ttl(int);void Mcast_set_if(int, const char *, u_int);void Mcast_set_loop(int, int);void Mcast_set_ttl(int, int);#endifuint16_t in_cksum(uint16_t *, int);#ifndef HAVE_GETADDRINFO_PROTOint getaddrinfo(const char *, const char *, const struct addrinfo *,struct addrinfo **);void freeaddrinfo(struct addrinfo *);char*gai_strerror(int);#endif#ifndef HAVE_GETNAMEINFO_PROTOint getnameinfo(const SA *, socklen_t, char *, size_t, char *, size_t, int); #endif#ifndef HAVE_GETHOSTNAME_PROTOint gethostname(char *, int);#endif#ifndef HAVE_HSTRERROR_PROTOconst char*hstrerror(int);#endif#ifndef HAVE_IF_NAMETOINDEX_PROTOunsigned int if_nametoindex(const char *);char*if_indextoname(unsigned int, char *);void if_freenameindex(struct if_nameindex *); struct if_nameindex *if_nameindex(void);#endif#ifndef HAVE_INET_PTON_PROTOint inet_pton(int, const char *, void *);const char*inet_ntop(int, const void *, char *, size_t);#endif#ifndef HAVE_INET_ATON_PROTOint inet_aton(const char *, struct in_addr *);#endif#ifndef HAVE_PSELECT_PROTOint pselect(int, fd_set *, fd_set *, fd_set *,const struct timespec *, const sigset_t *);#endif#ifndef HAVE_SOCKATMARK_PROTOint sockatmark(int);#endif#ifndef HAVE_SNPRINTF_PROTOint snprintf(char *, size_t, const char *, ...);#endif/* prototypes for our own library wrapper functions */ void Connect_timeo(int, const SA *, socklen_t, int);int Family_to_level(int);struct addrinfo *Host_serv(const char *, const char *, int, int); const char*Inet_ntop(int, const void *, char *, size_t); void Inet_pton(int, const char *, void *);char*If_indextoname(unsigned int, char *);unsigned int If_nametoindex(const char *);struct if_nameindex*If_nameindex(void);char**My_addrs(int *);ssize_t Read_fd(int, void *, size_t, int *);int Readable_timeo(int, int);ssize_t Recvfrom_flags(int, void *, size_t, int *, SA *, socklen_t *, struct unp_in_pktinfo *);Sigfunc *Signal(int, Sigfunc *);Sigfunc *Signal_intr(int, Sigfunc *);int Sock_bind_wild(int, int);char*Sock_ntop(const SA *, socklen_t);char*Sock_ntop_host(const SA *, socklen_t);int Sockfd_to_family(int);int Tcp_connect(const char *, const char *);int Tcp_listen(const char *, const char *, socklen_t *);int Udp_client(const char *, const char *, SA **, socklen_t *);int Udp_connect(const char *, const char *);int Udp_server(const char *, const char *, socklen_t *);ssize_t Write_fd(int, void *, size_t, int);int Writable_timeo(int, int);/* prototypes for our Unix wrapper functions: see {Sec errors} */ void*Calloc(size_t, size_t);void Close(int);void Dup2(int, int);int Fcntl(int, int, int);void Gettimeofday(struct timeval *, void *);int Ioctl(int, int, void *);pid_t Fork(void);void*Malloc(size_t);int Mkstemp(char *);void*Mmap(void *, size_t, int, int, int, off_t);int Open(const char *, int, mode_t);void Pipe(int *fds);ssize_t Read(int, void *, size_t);void Sigaddset(sigset_t *, int);void Sigdelset(sigset_t *, int);void Sigemptyset(sigset_t *);void Sigfillset(sigset_t *);int Sigismember(const sigset_t *, int);void Sigpending(sigset_t *);void Sigprocmask(int, const sigset_t *, sigset_t *);char*Strdup(const char *);long Sysconf(int);void Sysctl(int *, u_int, void *, size_t *, void *, size_t);void Unlink(const char *);pid_t Wait(int *);pid_t Waitpid(pid_t, int *, int);void Write(int, void *, size_t);/* prototypes for our stdio wrapper functions: see {Sec errors} */ void Fclose(FILE *);FILE*Fdopen(int, const char *);char*Fgets(char *, int, FILE *);FILE*Fopen(const char *, const char *);void Fputs(const char *, FILE *);/* prototypes for our socket wrapper functions: see {Sec errors} */ int Accept(int, SA *, socklen_t *);void Bind(int, const SA *, socklen_t);void Connect(int, const SA *, socklen_t);void Getpeername(int, SA *, socklen_t *);void Getsockname(int, SA *, socklen_t *);void Getsockopt(int, int, int, void *, socklen_t *);#ifdef HAVE_INET6_RTH_INITint Inet6_rth_space(int, int);void*Inet6_rth_init(void *, socklen_t, int, int);void Inet6_rth_add(void *, const struct in6_addr *);void Inet6_rth_reverse(const void *, void *);int Inet6_rth_segments(const void *);struct in6_addr *Inet6_rth_getaddr(const void *, int);#endif#ifdef HAVE_KQUEUEint Kqueue(void);int Kevent(int, const struct kevent *, int,struct kevent *, int, const struct timespec *);#endifvoid Listen(int, int);#ifdef HAVE_POLLint Poll(struct pollfd *, unsigned long, int);#endifssize_t Readline(int, void *, size_t);ssize_t Readn(int, void *, size_t);ssize_t Recv(int, void *, size_t, int);ssize_t Recvfrom(int, void *, size_t, int, SA *, socklen_t *);ssize_t Recvmsg(int, struct msghdr *, int);int Select(int, fd_set *, fd_set *, fd_set *, struct timeval *);void Send(int, const void *, size_t, int);void Sendto(int, const void *, size_t, int, const SA *, socklen_t);void Sendmsg(int, const struct msghdr *, int);void Setsockopt(int, int, int, const void *, socklen_t);void Shutdown(int, int);int Sockatmark(int);int Socket(int, int, int);void Socketpair(int, int, int, int *); void Writen(int, void *, size_t); void err_dump(const char *, ...); void err_msg(const char *, ...); void err_quit(const char *, ...); void err_ret(const char *, ...); void err_sys(const char *, ...);#endif/* __unp_h */。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
我们主要使用Internet所以sin_family一般为AF_INET,sin_addr设置为INADDR_ANY表示可以 和任何的主机通信,sin_port是我们要监听的端口号.sin_zero[8]是用来填充的. bind将本地的端口同socket返回的文件描述符捆绑在一起.成功是返回0,失败的情况和socket一样
struct sockaddr_in{
unsigned short sin_family;
unsigned short int sin_port;
struct in_addr sin_addr;
1.1 客户端程序和服务端程序
网络程序和普通的程序有一个最大的区别是网络程序是由两个部分组成的--客户端和服务器端.
网络程序是先有服务器程序启动,等待客户端的程序运行并建立连接.一般的来说是服务端的程序 在一个端口上监听,直到有一个客户端的程序发来了请求.
1.2 常用的命令
由于网络程序是有两个部分组成,所以在调试的时候比较麻烦,为此我们有必要知道一些常用的网络命令
type:我们网络程序所采用的通讯协议(SOCK_STREAM,SOCK_DGRAM等) SOCK_STREAM表明我们用的是TCP协议,这样会提供按顺序的,可靠,双向,面向连接的比特流. SOCK_DGRAM 表明我们用的是UDP协议,这样只会提供定长的,不可靠,无连接的通信.
protocol:由于我们指定了type,所以这个地方我们一般只要用0来代替就可以了 socket为网络通讯做基本的准备.成功时返回文件描述符,失败时返回-1,看errno可知道出错的详细情况.
exit(1);
}
while(1)
{
/* 服务器阻塞,直到客户程序建立连接 */
sin_size=sizeof(struct sockaddr_in);
if((new_fd=accept(sockfd,(struct sockaddr *)(&client_addr),&sin_size))==-1)
1.3 TCP/UDP介绍
TCP(Transfer Control Protocol)传输控制协议是一种面向连接的协议,当我们的网络程序使用 这个协议的时候,网络可以保证我们的客户端和服务端的连接是可靠的,安全的.
UDP(User Datagram Protocol)用户数据报协议是一种非面向连接的协议,这种协议并不能保证我们 的网络程序的连接是可靠的,所以我们现在编写的程序一般是采用TCP协议的.
connect函数是客户端用来同服务端连接的.成功时返回0,sockfd是同服务端通讯的文件描述符 失败时返回-1.
2.6 实例
服务器端程序
/******* 服务器程序 (server.c) ************/
#include <stdlib.h>;
#include <stdio.h>;
2.3 listen
int listen(int sockfd,int backlog)
sockfd:是bind后的文件描述符.
backlog:设置请求排队的最大长度.当有多个客户端程序和服务端相连时, 使用这个表示可以介绍的排队长度. listen函数将bind的文件描述符变为监听套接字.返回的情况和bind一样.
if(argc!=2)
{
fprintf(stderr,"Usage:%s portnumber\a\n",argv[0]);
exit(1);
}
if((portnumber=atoi(argv[1]))<0)
{
fprintf(stderr,"Usage:%s portnumber\a\n",argv[0]);
netstat
命令netstat是用来显示网络的连接,路由表和接口统计等网络的信息.netstat有许多的选项 我们常用的选项是 -an 用来显示详细的网络状态.至于其它的选项我们可以使用帮助手册获得详细的情况.
telnet
telnet是一个用来远程控制的程序,但是我们完全可以用这个程序来调试我们的服务端程序的. 比如我们的服务器程序在监听8888端口,我们可以用telnet localhost 8888来查看服务端的状况.
fprintf(stderr,"Bind error:%s\n\a",strerror(errno));
exit(1);
}
/* 监听sockfd描述符 */
if(listen(sockfd,5)==-1)
{
fprintf(stderr,"Listen error:%s\n\a",strerror(errno));
#include <stdlib.h>;
#include <stdio.h>;
#include <errno.h>;
#include <string.h>;
#include <netdb.h>;
#include <sys/types.h>;
#include <netinet/in.h>;
2.1 socket
int socket(int domain, int type,int protocol)
domain:说明我们网络程序所在的主机采用的通讯协族(AF_UNIX和AF_INET等). AF_UNIX只能够用于单一的Unix系统进程间通信,而AF_INET是针对Internet的,因而可以允许在远程 主机之间通信(当我们 man socket时发现 domain可选项是 PF_*而不是AF_*,因为glibc是posix的实现 所以用PF代替了AF,不过我们都可以使用的).
exit(1);
}
/* 这个通讯已经结束 */
close(new_fd);
/* 循环下一个 */
}
close(sockfd);
exit(0);
}
客户端程序
/******* 客户端程序 client.c ************/
{
fprintf(stderr,"Accept error:%s\n\a",strerror(errno));
exit(1);
}
fprintf(stderr,"Server get connection from %s\n",
exit(1);
}
/* 服务器端填充 sockaddr结构 */
bzero(&server_addr,sizeof(struct sockaddr_in));
server_addr.sin_family=AF_INET;
server_addr.sin_addr.s_addr=htonl(INADDR_ANY);
server_addr.sin_port=htons(portnumber);
/* 捆绑sockfd描述符 */
if(bind(sockfd,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr))==-1)
{
struct sockaddr{
unisgned short as_family;
cha兼容性,我们一般不用这个头文件,而使用另外一个结构(struct sockaddr_in) 来代替.在<unix/in.h>;中有sockaddr_in的定义
2.4 accept
int accept(int sockfd, struct sockaddr *addr,int *addrlen)
sockfd:是listen后的文件描述符.
addr,addrlen是用来给客户端的程序填写的,服务器端只要传递指针就可以了. bind,listen和accept是服务器端用的函数,accept调用时,服务器端的程序会一直阻塞到有一个 客户程序发出了连接. accept成功时返回最后的服务器端的文件描述符,这个时候服务器端可以向该描述符写信息了. 失败时返回-1
#include <errno.h>;
#include <string.h>;
#include <netdb.h>;
#include <sys/types.h>;
#include <netinet/in.h>;
#include <sys/socket.h>;
int main(int argc, char *argv[])
2.2 bind
int bind(int sockfd, struct sockaddr *my_addr, int addrlen)
sockfd:是由socket调用返回的文件描述符.
addrlen:是sockaddr结构的长度.
my_addr:是一个指向sockaddr的指针. 在<unix/socket.h>;中有 sockaddr的定义
{
int sockfd,new_fd;
struct sockaddr_in server_addr;
struct sockaddr_in client_addr;
int sin_size,portnumber;
char hello[]="Hello! Are You Fine?\n";