实验三socket编程实验指导_第1页
实验三socket编程实验指导_第2页
实验三socket编程实验指导_第3页
实验三socket编程实验指导_第4页
实验三socket编程实验指导_第5页
已阅读5页,还剩5页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、实验三 socket套接字编程实验指导一、Sockets编程基础知识网络编程就是通过计算机网络与其他程序进行通信的程序,Socket编程是网络编程的主流工具。Socket API是实现进程间通信的一种编程设施,也是一种为进程间提供底层抽象的机制。尽管应用开发人员很少需要在该层编写代码,但是理解socket API还是非常重要的。主要有两点原因:第一,高层设施是构建于socket API之上的,它们是利用socket API提供的操作来实现。第二,对于响应时间要求较高或运行于有限资源平台上的应用,甚至socket API是唯一可用的进程间通信设施。socket API出现于20世纪80年代早期,

2、作为Berkeley Unix(BSD 4.2)操作系统程序库来通过进程间通信功能。现在主流操作系统都提供socket API。在基于Unix系统中,如BSD、Linux系统,socket API是操作系统内核的一部分;在MS-DOS、Windows OS、OS/2等操作系统中,socket API是以程序库形式提供的,如在Windows系统中,socket API被称为Winsock。Socket接口规范可以适用多种通讯协议,主要是TCP/IP。TCP/IP是计算机互联最常适用的网络通讯协议,TCP/IP的核心部分由网络操作系统的内核实现,应用程序通过编程接口来访问TCP/IP,应用程序通讯

3、的方式有图3-1所示。应用程序1应用程序2网络编程接口,如Socket网络通讯服务接口,如TCP/IP操作系统,如Unix或者Windows物理通讯介质图3-1:应用程序通信方式TCP/IP使用一个网络地址和一个服务端口号来惟一地标识设备。网络地址标识网络上的特定设备;端口号标识要连接到的该设备上的特定服务。网络通讯的基本模式如下:每一台通讯的主机都有一个本网络环境中惟一的IP地址,一台主机上往往有多个通讯程序存在,每个这样的程序都要占用一个通讯端口。因此,一个IP地址,一个通讯端口,就能确定一个通讯程序的位置。二、Socket通讯连接方式Socket主要有三种通讯方式:流式Socket、数据

4、报Socket和原始Socket。1.流式Socket(SOCK_STREAM)流式套接字提供了基于Unix操作系统的流式I/O的数据传输模式,它仅仅支持通过可靠的、面向连接的通信,类似于电话系统服务,即每一次完整的数据传输都要经过建立连接、使用连接、终止连接的过程、在数据传输过程中,各数据分组不携带目的地址,而使用连接号(connect ID)。从本质上看,连接是一个管道,收发数据不但顺序一致,而且内容相同。Socket编程中,双方进程可以单独创建流式Socket,再在socket之间形成连接。一旦数据作为字符流被写入发送者进程,然后接收者通过socket来读取该数据。面向连接通信能确保数据

5、沿预先建立的连接安全有序地传输。 服务器使用两个Socket:一个接收连接;一个发送/接收数据。见图5-2。客户1客户2连接Socket数据Socket服务器连接操作Send/Receive操作图3-2:流式Socket通信2.数据报Socket(SOCK_DGRAM)数据报套接字定义了一种无连接的服务,数据通过相互独立的报文进行传输,是无序的,并且不保证可靠、无差错。类似于邮政系统服务。每个分组都携带完整的目的地址,各分组独立传送。无连接服务不能保证分组的先后顺序,不进行分组出错的恢复与重传,不保证传输的可靠性。UDP协议提供无连接的数据报服务。它使用数据报协议UDP。Socket API运

6、行时进程A传输层软件进程ASocket API运时行传输层软件图3-3:无连接数据包socket3.原始Socket原始套接字允许对底层协议如IP或ICMP直接访问,它功能强大但使用不便主要用于一些协议的开发。三、基于C的面向连接的Socket编程模型TCP协议是面向连接协议,它提供了一系列的数据纠错功能,可以保证在网络上传输的数据及时、无误的传给接收方。因此面向连接协议的Socket编程模型应用最为广泛,基于连接协议的服务是设计客户端/服务器应用程序时的标准。编程模型如图3-4所示。模型中,服务器端的处理:(1)使用socket系统调用,生成一个TCP协议模块与应用程序之间进行通信的套接字;

7、使用bind系统调用指定端口号;(2)使用bind系统调用指定端口号(1024以上);(3)使用listen系统调用,指定连接接收队列的长度,并等待来自客户端的连接请求。前三步完成了启动服务器程序的工作。一旦listen监听到有客户端的连接,就调用accept接收连接。希望与服务器通信的进程称为客户,客户所运行的计算机环境称为客户端,有时两个概念混用。客户端的处理:(1)使用socket系统调用,打开TCP协议模块与应用程序之间的通信线路;(2)使用connect系统调用,指定IP地址和端口号,和服务器相应的服务应用程序建立TCP协议的连接请求;客户端和服务器程序在建立连接后,使用send和r

8、ecv调用完成数据的发送和接收工作。等待数据传送结束后,各自调用close关闭套接字。使用TCP协议的Socket通信程序包括服务程序和客户程序。服务器端客户端socketbindlistensocketconnectacceptrecvsendrecvclosesendclose阻塞自己等待客户连接建立连接请求数据应答数据图3-4:基于C的面向连接的socket编程模型基于C的Socket编程相关函数和数据类型1.sockadd和sockaddr_in结构: sockaddr 结构struct sockaddrunsigned short sa_family;/*地址族,AF_xxx有IPV

9、4与IPV6等*/charsa_data14;/*14字节的协议地址*/;sa_family一般为AF_INET,表示Internet协议族,如是AF_UNIX表示UNIX协议簇;sa_data中包含该socket的IP地址和端口号。 in_add结构,用来存储四字节的IP地址struct in_addrunsigned longs_addr; sockaddr_in结构struct sockaddr_inshort intsin_family;/*地址族*/unsigned short intsin_port;/*端口号*/struct in_add sin_addr;/*IP地址*/uns

10、igned charsin_zero8;/*填充0以保持与struct sockaddr同样大小*/;该结构中sin_zero使得sockaddr和sockaddr_in指针类型相互转换;sin_port和sin_addr必须是网络字节顺序,因为它们被封装在包的IP和UDP层,而sin_family不发送到网络上可以是本机字节顺序。相关函数1socket()函数该函数用于根据指定的地址族、数据类型和协议来分配一个套接字的描述字及其所用的资源。Socket函数原型为:int socket( int domain , int type , int protocol ) ;a、 参数domain指定

11、地址描述,一般为AP_INET;b、 参数type指定socket类型:SOCK_STREAM和SOCK_DGRAM;c、参数protocol通常为0;d、 函数返回值为一个整型socket描述符,在bind函数中调用。2bind()函数该函数用于将一个本地地址与一个套接字绑定在一起。int bind( int sockfd , struct sockadd* my_addr , int addrlen) ;a、sockfd:socket描述符,使用socket函数返回值,将该socket与本机上的一个端口相关联。在设计服务器端程序是需要调用bind函数,以在该端口上监听服务请求;而客户端一般

12、不需要调用bind函数,因为只需知道服务器IP地址,并不关心客户通过哪个端口与服务器建立连接,内核会自动选择一个未被占用的端口供客户端来使用。b、my_addr:指向包含本机IP地址及端口号等信息的sockaddr类型的指针。c、addrlen:sizeof( struct sockaddr)的值。d、bind函数返回值:为-1表示遇到错误,并且errno中包含相应的错误码。3connect()函数与远程服务器建立一个TCP连接。int connect(int sockfd, struct sockaddr* serv_addr, int addrlen);a、sockfd:目的服务器的soc

13、ket描述符。b、serv_addr:指向包含目的服务器的IP地址及端口号的指针。c、addrlen:sizeof( struct sockaddr)的值。d、connect函数返回值:为-1表示遇到错误,并且errno中包含相应的错误码,进行服务器端程序设计时不需调用connect函数。4listen()函数在服务器端程序中,当socket与某一端口绑定后,需要监听该端口,及时处理到达该端口上的服务请求。int listen(int sockfd, int backlog);a、sockfd:Socket系统调用返回的socket描述符。b、backlog:指定在请求队列中允许的最大请求数,

14、进入的连接请求将在队列中等待接收backlog限制了队列中等待服务的请求数目,系统缺省值为20。c、listen函数返回值:为-1表示遇到错误,并且errno中包含相应的错误码。5accept()函数当某个客户端试图与服务器监听的端口连接时,该连接请求将排队等待服务器用accept接收它并为其建立一个连接。int accept(int sockfd, struct sockaddr* addr, int* addrlen);a、sockfd:被监听的socket描述符。b、addr:sockaddr类型的指针变量,用来存放提出连接请求服务的主机信息。c、accept函数返回值:为-1表示遇到错

15、误,并且errno中包含相应的错误码,如果没有错误,accept()函数返回一个新想socket描述符,供这个新连接来实用,而服务器可以继续在以前的socket上监听,同时可以在新的socket描述符上进行数据发送和数据接收(sent()和recv()操作)。6sent()和recv()函数用于在面向连接(TCP)的socket上进行数据传输。send()函数原型:int send(int sockfd, const void* msg, int len, int flags) ;a、sockfd:用于传输数据的socket描述符。b、msg:是一个指向要发送数据的指针。c、len:以字节为单

16、位的数据的长度。d、flags:一般情况下置为0。e、函数返回值:为-1表示遇到错误,并且errno中包含相应的错误码,否则返回所发送数据的总数,该数字可能小于len中所规定的大小。 recv()函数原型: int recv(int sockfd, void* buf, int len, unsigned int flags);a、sockfd:是接收数据的socket描述符。b、buf:是存放接收数据的缓冲区。c、len:以字节为单位的缓冲区的长度。d、flags:一般情况下置为0。e、函数返回值:为-1表示遇到错误,并且errno中包含相应的错误码,无错则返回读入的字节数,如果连接被中止,

17、返回0。7sendto()和recvfrom()函数这两个函数是利用数据报方式(UDP)进行数据传输。在无连接的数据报socket方式下,由于本地socket并没有与远程机器建立连接,所以在发送数据时应指明目的地址。sendto()原型:int sendto(int sockfd, const void* msg, int len, unsigned int flags, const struct sockaddr* to, int tolen);a、sockfd:用于传输数据的socket描述符。b、msg:是一个指向要发送数据的指针。c、len:以字节为单位的数据的长度。d、flags:一

18、般情况下置为0。e、函数返回值:为-1表示遇到错误,并且errno中包含相应的错误码,否则返回所发送数据的总数,该数字可能小于len中所规定的大小。f、表示目的机器的IP地址和端口号。g、tolen:被赋值为sizeof(struct sockaddr)。 recvfrom函数原型:int recv(int sockfd, void* buf, int len, unsigned int flags, struct sockaddr* from, int fromlen);a、sockfd:是接收数据的socket描述符。b、buf:是存放接收数据的缓冲区。c、len:以字节为单位的缓冲区的长

19、度。d、flags:一般情况下置为0。e、函数返回值:为-1表示遇到错误,并且errno中包含相应的错误码,无错则返回读入的字节数,如果连接被中止,返回0。f、from:保存源机器的IP地址和端口号。g、fromlen:常被赋值为sizeof(struct sockaddr)。当对于数据报socket调用了connect()函数时,也可以用send()和recv()进行数据传输,但该socket仍然是数据报socket,并利用传输层的UDP服务。但是在发送或接收数据报时,内核会自动为它加上目的地址和源地址信息。8close()和shutdown()函数当所有的数据操作结束后,可以调用close

20、函数来释放该socket资源,从而停止在该socket上的任何数据操作。也可以调用shutdown函数,允许只停止在某个方向上的数据传输,而另一个方向上的数据传输继续进行。例如可以关闭某一个socket上的写操作uo允许继续在该socket上接收数据,直到读入所有数据。但是,shutdown函数并不关闭套接字所占用的所有资源,除非调用close函数来释放。看看两个函数原型:close(int sockfd);shutdown(int sockfd, int how);how参数的值和含义: 0:不允许继续接收数据; 1:不允许继续发送数据; 2:不允许继续发送和接收数据。 shutdown在操

21、作成功时返回0,错误时返回-1,并置errno值。9字节顺序转换函数htons():Host to Network Short的缩写,该函数将主机的无符合短整型数字节顺序转换成网络字节顺序。htonl():Host to Network Long的缩写,该函数将主机的无符合长整型数字节顺序转换成网络字节顺序。ntohs():Network to Host Short的缩写,该函数将无符号短整型数从网络字节顺序转换为主机字节顺序。ntohl():Network to Host long的缩写,该函数将无符号长整型数从网络字节顺序转换为主机字节顺序。四、服务器程序代码#include "

22、stdafx.h"#include <stdio.h>#include <stdlib.h>#include <errno.h>#include <string.h>#include <sys/types.h>#include<conio.h> #include<winsock2.h>#include<windows.h> #pragma comment(lib,"ws2_32.lib") #define MYPORT 3490 /*定义用户连接端口*/ #define

23、 BACKLOG 10 /*多少等待连接控制*/ #define SERVER_IP_ADDR "192.168.1.102" /*服务器的IP地址*/ int _tmain(int argc, _TCHAR* argv) SOCKET sock, msgsock; int length = 0; struct sockaddr_in server; struct sockaddr tcpaddr; char buf1024 = "" int rval= 0, len= 0, err = 0; WORD wVersionRequested; WSADAT

24、A wsaData; /*指定socket版本,否则创建socket失败,即使创建socket返回值不为-1,但是bind时会失败*/ wVersionRequested = MAKEWORD( 2, 2 ); err = WSAStartup( wVersionRequested, &wsaData ); if ( err != 0 ) return -1; /* 建立套接字*/ sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) perror("opening stream socket"); exi

25、t(1); /* 使用任意端口命名套接字*/ server.sin_family = AF_INET; server.sin_port = htons(MYPORT); server.sin_addr.s_addr = inet_addr(SERVER_IP_ADDR); memset(server.sin_zero, 0, sizeof(server.sin_zero); /将服务器地址与socket绑定在一起 rval = bind(sock, (struct sockaddr *)&server, sizeof(server); if (rval < 0) perror(&

26、quot;binding stream socket"); exit(1); / 找出指定的端口号并打印出来 length = sizeof(server); if (getsockname(sock, (struct sockaddr *)&server, &length) < 0) perror("getting socket name"); exit(1); printf("socket port #%dn", ntohs(server.sin_port); / 开始接收连接,最大请求数为 listen(sock,

27、5); len = sizeof(struct sockaddr); do msgsock = accept(sock, (struct sockaddr *)&tcpaddr, (int *)&len); if (msgsock = -1) perror("accept"); else memset(buf, 0, sizeof(buf); if ( (rval = recv(msgsock, buf, sizeof(buf),0) < 0) perror("reading stream message"); if (rval =

28、 0) printf("->%sn", buf); closesocket(msgsock); while (TRUE); /* 因为这个程序已经有了一个无限循环,所以套接字"sock"从来不显式关闭。然而,当进程被杀死或正常终止时,所有套接字都将自动地被关闭。*/ closesocket(msgsock);return 0;五、客户端程序代码#include "stdafx.h"#include <stdio.h>#include <stdlib.h>#include <errno.h>#i

29、nclude <string.h>#include <sys/types.h>#include <conio.h> #include <winsock2.h> #include <windows.h> #pragma comment(lib,"ws2_32.lib") #define PORT 3490 /* 客户机连接远程主机的端口*/ #define MAXDATASIZE 100 /* 每次可以接收的最大字节*/ int _tmain(int argc, _TCHAR* argv) WORD wVersionRequested; WSADATA wsaData; int err = 0 ,rval =

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论