ImageVerifierCode 换一换
格式:DOCX , 页数:49 ,大小:50.41KB ,
资源ID:5746371      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bingdoc.com/d-5746371.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(Socket编程知识必学Word格式.docx)为本站会员(b****1)主动上传,冰点文库仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰点文库(发送邮件至service@bingdoc.com或直接QQ联系客服),我们立即给予删除!

Socket编程知识必学Word格式.docx

1、 为什么说它们是“无连接”的呢?因为它(UDP)不像流式套接字那样维护一个打开的连接,你只需要把数据打成一个包,把远程的IP 贴上去,然后把这个包发送出去。这个过程是不需要建立连接的。 UDP 的应用例子有: tftp, bootp 等。 那么,数据包既然会丢失,怎样能保证程序能够正常工作呢? 事实上,每个使用UDP的程序都要有自己的对数据进行确认的协议。 比如, TFTP 协议定义了对于每一个发送出去的数据包,远程在接受到之后都要回送一个数据包告诉本地程序:“我已经拿到了!”(一个 “ACK” 包)。如果数据包发的送者在5 秒内没有的得到回应,它就会重新发送这个数据包直到数据包接受者回送了

2、“ACK” 信号。这些知识对编写一个使用UDP 协议的程序员来说是非常必要的。 无连接服务器一般都是面向事务处理的,一个请求一个应答就完成了客户程序与服务程序之间的相互作用。 面向连接服务器处理的请求往往比较复杂,不是一来一去的请求应答所能解决的,而且往往是并发服务器 套接字工作过程如下: 服务器首先启动 通过调用socket()建立一个套接字, 然后调用bind()将该套接字和本地网络地址联系在一起, 再调用listen()使套接字做好侦听的准备,并规定它的请求队列的长度, 之后就调用accept()来接收连接。 客户在建立套接字 然后就可调用connect()和服务器建立连接。 客户机和服

3、务器之间就可以通过调用read()和write()来发送和接收数据。 最后,待数据传送结束后,双方调用close()关闭套接字。对流式套接字你所需要做的只是调用send() 函数来发送数据。而对于数据报套接字,你需要自己加个信息头,然后调用sendto() 函数把数据发送出去 原始套接字 原始套接字主要用于一些协议的开发,可以进行比较底层的操作。它功能强大,但是没有上面介绍的两种套接字使用方便,一般的程序也涉及不到原始套接字套接字结构struct sockaddr这个结构用来存储套接字地址。数据定义:struct sockaddr unsigned short sa_family; /* ad

4、dress族, AF_xxx */ char sa_data14;/* 14 bytes的协议地址 */;sa_family 一般来说,都是 “AF_INET”。sa_data 包含了一些远程电脑的地址、端口和套接字的数目,它里面的数据是杂溶在一切的。为了处理struct sockaddr, 程序员建立了另外一个相似的结构struct sockaddr_in (“in” 代表 “Internet”):struct sockaddr_in short int sin_family;/* Internet地址族 */ unsigned short int sin_port; /* 端口号 */ s

5、truct in_addr sin_addr; /* Internet地址 */ char sin_zero8; /* 添0(和struct sockaddr一样大小)*/注意: 1)这个结构提供了方便的手段来访问socket address(struct sockaddr)结构中的每一个元素。 2)sin_zero8 是为了是两个结构在内存中具有相同的尺寸 要把sin_zero 全部设成零值(使用bzero()或memset()函数)。 3)一个指向struct sockaddr_in 的指针可以声明指向一个sturct sockaddr 的结构。所以虽然socket() 函数需要一个str

6、uctaddr * ,你也可以给他一个sockaddr_in * 。 4)在struct sockaddr_in 中,sin_family 相当于 在struct sockaddr 中的sa_family,需要设成 “AF_INET”。 5)一定要保证sin_port 和sin_addr 必须是网络字节顺序(见下节)!2struct in_addr ( 因特网地址 (a structure for historical reasons) ) struct in_addr unsigned long s_addr; ; 如果你声明了一个 ina 作为一个struct sockaddr_in 的结

7、构, 那么“ina.sin_addr.s_addr”就是4 个字节的IP 地址(按网络字节顺序排放)。 需要注意的是,即使你的系统仍然使用联合而不是结构来表示struct in_addr,你仍然可以用上面的方法得到4 个字节的IP 地址(一些 #defines 帮了你的忙)网络字节顺序 因为每一个机器内部对变量的字节存储顺序不同(有的系统是高位在前,底位在后,而有的系统是底位在前,高位在后),而网络传输的数据大家是一定要统一顺序的。 所以对与内部字节表示顺序和网络字节顺序不同的机器,就一定要对数据进行转换(比如IP 地址的表示,端口号的表示)。 但是内部字节顺序和网络字节顺序相同的机器该怎么办

8、呢?是这样的:它们也要调用转换函数,但是真正转换还是不转换是由系统函数自己来决定的。 有关的转化函数 我们通常使用的有两种数据类型:短型(两个字节)和长型(四个字节)。 下面介绍的这些转换函数对于这两类的无符号整型变量都可以进行正确的转换。 如果你想将一个短型数据从主机字节顺序转换到网络字节顺序的话,有这样一个函数htons: 它是以“h”开头的(代表“主机”); 紧跟着它的是“to”,代表“转换到”; 然后是“n”代表“网络”; 最后是“s”,代表“短型数据”。 H-to-n-s,就是htons() 函数(可以使用Hostto Network Short 来助记) 你可以使用 “n”,“h”

9、,“to”,“s”,“l”的任意组合.当然,你要在可能的情况下进行组合。比如,系统是没有stolh() 函数的(Short to Long Host?)。 下面给出套接字字节转换程序的列表: htons()“Host to Network Short” 主机字节顺序转换为网络字节顺序(对无符号短型进行操作4 bytes) htonl()“Host to Network Long”主机字节顺序转换为网络字节顺序(对无符号长型进行操作8 bytes) ntohs()“Network to Host Short “网络字节顺序转换为主机字节顺序(对无符号短型进行操作4 bytes) ntohl()“

10、Network to Host Long “网络字节顺序转换为主机字节顺序(对无符号长型进行操作8 bytes) 在struct sockaddr_in 中的sin_addr 和sin_port 他们的字节顺序都是网络字节顺序,而sin_family 却不是网络字节顺序的。为什么呢? 这个是因为sin_addr 和sin_port 是从IP 和UDP 协议层取出来的数据,而在IP 和UDP协议层,是直接和网络相关的,所以,它们必须使用网络字节顺序。 然而, sin_family 域只是内核用来判断struct sockaddr_in 是存储的什么类型的数据,并且, sin_family 永远也

11、不会被发送到网络上,所以可以使用主机字节顺序来存储socket() 函数 /* * * 取得套接字描述符!(记得我们以前说过的吗?它其实就是一个文件描述符) * * domain 需要被设置为 “AF_INET”,就像上面的struct sockaddr_in。 * type 参数告诉内核这个socket 是什么类型,“SOCK_STREAM”或是“SOCK_DGRAM”。 * protocol 通常为0 * return 如果发生错误,socket()函数返回 1 。全局变量errno 将被设置为错误代码。 */ #include sys/socket.h int socket(int do

12、main , int type , int protocol) 示例: if(sockfd = socket(AF_INET, SOCK_STREAM, 0) = -1) perror(create sock); return -1; else / printf(socket created.nbind() 函数/* 为套接字绑定一个端口号* 当你需要进行端口监听listen()操作,等待接受一个连入请求的时候,* 一般都需要经过这一步。比如网络泥巴(MUD),Telnet a.b.c.d 4000* * 如果你只是想进行连接一台服务器,也就是进行connect() 操作的时候,这一步并不是必

13、须的。* sockfd 是由socket()函数返回的套接字描述符* my_addr 是一个指向struct sockaddr 的指针,包含有关你的地址的信息:名称、端口和IP 地址。* addrlen 可以设置为sizeof(struct sockaddr)* return 调用错误的时候,返回 -1 作为错误发生的标志。errno 的值为错误代码。#include #define MYPORT 4000main() int sockfd ; struct sockaddr_in my_addr ; sockfd = socket(AF_INET, SOCK_STREAM, 0); /* 在

14、你自己的程序中要进行错误检查!! my_addr.sin_family = AF_INET ; /* 主机字节顺序 */ my_addr.sin_port = htons(MYPORT); /* 网络字节顺序,短整型 */ my_addr.sin_addr.s_addr = inet_addr(166.111.69.52) ; bzero(&(my_addr.sin_zero), 8); /* 将整个结构剩余部分数据设为0 */ bind (sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr); /* 不要忘记在你自己的程序中

15、加入判断bind 错误的代码! 注意: 是网络字节顺序, 短整型 my_addr.sin_addr.s_addr 也是网络字节顺序。 最后,bind()可以在程序中自动获取你自己的IP 地址和端口。 my_addr.sin_port = 0 ; /* 随机选择一个端口 */ my_addr.sin_addr.s_addr = INADDR_ANY ; /* 使用自己的地址 */ 如上,通过设置my_addr.sin_port 为0,bind()可以知道你要它帮你选择合适的端口; 通过设置my_addr.sin_addr.s_addr 为INADDR_ANY,bind()知道你要它将s_addr

16、 填充为运行这个进程的机器的IP。 这一切都可以要求bind()来自动的帮助你完成。 如果你注意到了一些细节的话,你可能会发现我并没有将INADDR_ANY 转换为网络字节顺序!是这样的,INADDR_ANY的值为0,0 就是0,无论用什么顺序排列位的顺序,它都是不变的。 有读者会想了,因为我用的INADDR_ANY 是一个#define,那么如果将我的程序移植到另外一个系统,假如那里的INADDR_ANY是这样定义的: #define INADDR_ANY 100, 那么我的程序不是就会不运行了吗?那么下面这段代码就OK 了: my_addr.sin_port = htons(0); /*

17、随机选择一个未用的端口 */ my_addr.sin_addr.s_addr = htonl(INADDR_ANY) ; /* 使用自己的IP地址 */ 现在我们已经是这么的严谨,对于任何数值的INADDR_ANY调用bind 的时候就都不会有麻烦了。 另外一件必须指出的事情是: 当你调用bind()的时候,不要把端口数设置的过小!小于1024 的所有端口都是保留下来作为系统使用端口的,没有root 权利无法使用。你可以使用1024 以上的任何端口,一直到65535 :你所可能使用的最大的端口号(当然,你还要保证你所希望使用的端口没有被其他程序所使用)。 最后注意有关bind()的是: 有时候

18、你并不一定要调用bind()来建立网络连接。比如你只是想连接到一个远程主机上面进行通讯,你并不在乎你究竟是用的自己机器上的哪个端口进行通讯(比如Telnet),那么你可以简单的直接调用connect()函数,connect()将自动寻找出本地机器上的一个未使用的端口,然后调用 bind()来将其socket 绑定到那个端口上。connect() 函数/* 套接字文件描述符,由socket()函数返回的* serv_addr 是一个存储远程计算机的IP 地址和端口信息的结构 应该是sizeof(struct sockaddr) 如果发生了错误(比如无法连接到远程主机,或是远程主机的指定端口无法进

19、行连接等)它将会返回错误值 -1* 全局变量errno将会存储错误代码int connect (int sockfd, struct sockaddr *serv_addr, int addrlen);#define DEST_IP “166.111.69.52”#define DEST_PORT 23 /* 将用来存储远程信息 */ struct sockaddr_in dest_addr ; /* 注意在你自己的程序中进行错误检查! sockfd = socket(AF_INET, SOCK_STREAM, 0); dest_addr.sin_family = AF_INET ; dest

20、_addr.sin_port = htons(DEST_PORT(; dest_addr.sin_addr.s_addr = inet_addr(DEST_IP); /* 将剩下的结构中的空间置0 */(dest_addr.sin_zero), 8); /* 不要忘记在你的代码中对connect()进行错误检查! connect(sockfd, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr); 注意我们没有调用bind()函数。基本上,我们并不在乎我们本地用什么端口来通讯,是不是?我们在乎的是我们连到哪台主机上的哪个端口上。Linu

21、x 内核自动为我们选择了一个没有被使用的本地端口。listen() 函数* 等待别人连接,进行系统侦听请求* 当有人连接你的时候,你有两步需要做: 通过listen()函数等待连接请求 然后使用accept()函数来处理* 那么我们需要指定本地端口了,因为我们是等待别人的连接。所以,在listen()函数调用之前,我们需要使用bind() 函数来指定使用本地的哪一个端口数值* 如果你想在一个端口上接受外来的连接请求的话,那么函数的调用顺序为: socket(); bind(); listen(); 是一个套接字描述符,由socket()系统调用获得* backlog 是未经过处理的连接请求队列

22、可以容纳的最大数目(每一个连入请求都要进入一个连入请求队列,等待listen 的程序调用accept()函数来接受这个连接。当系统还没有调用accept()函数的时候,如果有很多连接,那么本地能够等待的最大数目就是 backlog 的数值。你可以将其设成5 到10 之间的数值(推荐) 错误返回-1, 并设置全局错误代码变量errnoint listen(int sockfd, int backlog);accept()函数* 当调用它的时候,大致过程是下面这样的: 有人从很远很远的地方尝试调用connect()来连接你的机器上的某个端口(当然是你已经在listen()的) 他的连接将被list

23、en 加入等待队列等待accept()函数的调用 你调用accept()函数,告诉他你准备连接 是正在listen() 的一个套接字描述符* addr 一般是一个指向struct sockaddr_in 结构的指针;里面存储着远程连接过来的计算机的信息(比如远程计算机的IP 地址和端口) 是一个本地的整型数值,在它的地址传给accept() 前它的值应该是sizeof(struct sockaddr_in);accept()不会在addr 中存储多余addrlen bytes 大小的数据。如果accept()函数在addr 中存储的数据量不足addrlen,则accept()函数会改变addrlen 的值来反应这个情况。 accept()函数将回返回一个新的套接字描述符,这个描述符就代表了这个连接 这时候你有了两个套接字描述符: 返回给你的那个就是和远程计算机的连接, 这时候你所得到的那个新的套接字描述符就可以进行send()操作和recv()操作了。 而第一个套接字描述符仍然在你的机器上原来的那个端口上listen() -1 来表明调用失败,同时全局变量errno 将会存储错误代码int accept(int sockfd, void *addr, int *addrlen);sys/types.h

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2