2024年2月9日发(作者:)
实验 6. Linux Socket 编程实验
1、实验目的:
(1) 了解 TCP/IP 协议;
(2) 掌握 socket 编程。
2、实验设备:
(1) PC 机的 VMware 虚拟机运行 Ubuntu Linux 系统;
(2) 两机对连的网络线;
(3) 带网口的测试计算机;
(4) WINDOWS“SOCKET TOOL”调试工具。
3、实验内容:
实现典型客户机/服务器程序中的服务器及客户机。
4、实验原理
4.1 客户机/服务器工作流程
使用TCP协议的客户机/服务器进程的工作过程如下图
4.2 Socket 编程相关函数
常用的socket函数有:socket,bind,listen,accept,connect,send,recv。
1)socket(建立连接)
表头文件:
#include
#include
定义函数:int socket(int family,int type,int protocol);
函数说明:socket()函数用来生成一个套接口描述字,也称为套接字,指
定协议簇和套接口。
参数:family指定协议族,type指明字节流方式,而protocol一般为0
Family的取值范围:
AF_LOCALUNIX协议族
AF_ROUTE路由套接口
AF_INETIPv4协议
AF_INET6IPv6协议
AF_KEY密钥套接口
参数type的取值范围:
SOCK_STREAMTCP套接口
SOCK_DGRAMUDP套接口
SOCK_PACKET支持数据链路访问
SOCK_RAM原始套接口
返回值:成功返回非负描述字,失败返回负值
2)bind(对socket定位)
表头文件:
#include
#include
定义函数:
Int bind(int sockfd,struct sockaddr * my_addr,int addrlen);
函数说明bind()用来设置给参数sockfd的socket一个名称。此名称由参数
my_addr指向一
sockaddr结构,对于不同的socketdomain定义了一个通用的数据结构
structsockaddr
{
unsignedshortintsa_family;
charsa_data[14];
};
sa_family为调用socket()时的domain参数,即AF_xxxx值。
sa_data最多使用14个字符长度。
此sockaddr结构会因使用不同的socketdomain而有不同结构定义,
例如使用
AF_INET
domain,其socketaddr结构定义便为
structsocketaddr_in
{
unsignedshortintsin_family;
uint16_tsin_port;
structin_addrsin_addr;
unsignedcharsin_zero[8];
};
structin_addr
{
uint32_ts_addr;
};
sin_family即为sa_family
sin_port为使用的port编号
sin_addr.s_addr为IP地址
sin_zero未使用。
参数socket为套接字,my_addr是一个指向特定协议地址结构的指针,
addrlen为sockaddr
的结构长度。
返回值成功则返回0,失败返回-1,错误原因存于errno中。
错误代码
EBADF参数sockfd非合法socket处理代码。
EACCESS权限不足
ENOTSOCK参数sockfd为一文件描述词,非socket。
3)listen(等待连接)
表头文件:
#include
定义函数:
Int listen(ints,intbacklog);
函数说明:
listen()用来等待参数s的socket连线。
参数backlog指定同时能处理的最大
连接要求,如果连接数目达此上限则client端将收到ECONNREFUSED的错误。
Listen()并未开始接收连线,只是设置socket为listen模式,真正接收client
端连线的是accept()。通常listen()会在socket(),bind()之后调用,接着才
调用accept()。
返回值成功则返回0,失败返回-1,错误原因存于errno
附加说明listen()只适用SOCK_STREAM或SOCK_SEQPACKET的socket类型。如
果
socket为AF_INET则参数backlog最大值可设至128。
错误代码
EBADF参数sockfd非合法socket处理代码
EACCESS权限不足
EOPNOTSUPP指定的socket并未支援listen模式。
4)accept
表头文件:
#include
#include
定义函数:
Int accept(int s,struct sockaddr * addr,int * addrlen);
函数说明accept()用来接受参数s的socket连线。参数s的socket必需先经
bind()、
listen()函数处理过,
当有连线进来时accept()会返回一个新的socket
处理代码,往后的数据传送与读取就是经由新的socket处理,而原来参数s的
socket能继续使用accept()来接受新的连线要求。连线成功时,参数addr所指
的结构会被系统填入远程主机的地址数据,参数addrlen为scokaddr的结构长
度。关于结构sockaddr的定义请参考bind()。
返回值成功则返回新的socket处理代码,失败返回-1,错误原因存于errno
中。
错误代码EBADF参数s非合法socket处理代码。
EFAULT参数addr指针指向无法存取的内存空间。
ENOTSOCK参数s为一文件描述词,非socket。
EOPNOTSUPP指定的socket并非SOCK_STREAM。
EPERM防火墙拒绝此连线。
ENOBUFS系统的缓冲内存不足。
ENOMEM核心内存不足。
5)connect(建立socket连线)
表头文件:
#include
#include
定义函数:
Int connect(int sockfd,struct sockaddr * serv_addr,int addrlen);
函数说明connect()用来将参数sockfd的socket连至参数serv_addr指定的
网络地址。结构sockaddr请参考bind()。参数addrlen为sockaddr的结构长度。
返回值成功则返回0,失败返回-1,错误原因存于errno中。
错误代码EBADF参数sockfd非合法socket处理代码
EFAULT参数serv_addr指针指向无法存取的内存空间
ENOTSOCK参数sockfd为一文件描述词,非socket。
EISCONN参数sockfd的socket已是连线状态
ECONNREFUSED连线要求被server端拒绝。
ETIMEDOUT企图连线的操作超过限定时间仍未有响应。
ENETUNREACH无法传送数据包至指定的主机。
EAFNOSUPPORTsockaddr结构的sa_family不正确。
EALREADYsocket为不可阻断且先前的连线操作还未完成。
6)send()和recv()这两个函数用于面向连接的socket上进行数据传输。
函数定义:
Int send(int sockfd,const void * msg,int len,int flags);
参数:
Sockfd是你想用来传输数据的socket描述符;
msg是一个指向要发送
数据的指针;Len是以字节为单位的数据的长度;flags一般情况下置为0(关于
该参数的用法可参照man手册)。
返回值:send()函数返回实际上发送出的字节数,可能会少于你希望发送的
数据。在程序中应该将send()的返回值与欲发送的字节数进行比较。当send()
返回值与len不匹配时,应该对这
种情况进行处理。
char*msg="Hello!";
intlen,bytes_sent;
......
len=strlen(msg);
bytes_sent=send(sockfd,msg,len,0);
......
函数定义:int recv(int sockfd,void * buf,int len,unsigned int flags);
参数:sockfd是接受数据的socket描述符;buf是存放接收数据的缓冲区;
len是缓冲的长度。Flags也被置为0。
返回值:Recv()返回实际上接收的字节数,当出现错误时,返回-1并置相应
的errno值。
sendto()和recvfrom()用于在无连接的数据报socket方式下进行数据传输。
由于本地socket并没有与远端机器建立连接,所以在发送数据时应指明目的地
址。
5、编译及运行
(1) 连接 PC 机和中央网关板的串口线;
(2) 打开 PC 机的超级终端,设置“115200,8,n,1”;
(3) 连接 PC 机和中央网关板的网络线;
(4) 设置 PC 机 IP 地址到”192.168.0.200”;
(5) 给中央网关板加电;
(6) 使用 arm-linux-gcc 编译文件 socketclient.c 为 socketclient;
(7) 将 socketclient 使用 FTP 下载到中央网关板,修改运行权限 chmod +x
socketclient;
(8) 运行 Windows 下 sockettool 调试工具,建立 TCP Server,端口 1002;(9) 运行编译后的程序:./socketclient “192.168.0.200” 1002;
6、实验现象
Socketclient 将连接到 server,输入的数据将在 server 端显示出来。
7、附录
7.1 计算机网络体系结构模式
所有的网络通信方式分为两种:线路交换和包交换。
所谓的线路交换,就是指再传输时在发送端和接收端之间建立一个特定的线路
连接,数据就可以在这条线路上传输。电话是采用的这种方式。
计算机网络则采用的是包交换,数据的发送端将要传输的数据分割成块,而每
个块经过适当的处理后形成一个数据包,包中有接收端的地址等必要信息,每个包
单独传输。包中的数据并不是限定死的,只要保证数据的正确传输即可,具体应该
定义哪些信息,则与使用的协议有关。
(1) OSI 标准
OSI标准是开放系统互联标准(OpenSystermInterconnection)即我们通常
所说的网络互联的七层框架,
他是1977年国际标准化组织提出的一种参考模型。
值得注意的是,OSI并没有提供一个可以实现的方法,它不是一个标准而只是一
个制定标准时使用的概念性的框架,更不是一个网络协议。
1)、物理层(PhysicalLayer):主要功能为定义了网络的物理结构,传输
的电磁标准,Bit流的编码及网络的时间原则,如分时复用及分频复用。决定了
网络连接类型(端到端或多端连接)及物理拓扑结构。说的通俗一些,这一层
主要负责实际的信号传输。
2)、链路层(DataLinkReview):在两个主机上建立数据链路连接,向物
理层传输数据信号,并对信号进行处理使之无差错并合理的传输。
3)、网络层(NetworkLayer):主要负责路由,选择合适的路径,进行阻
塞控制等功能。
4)、传输层(TransferLayer):最关键的一层,向拥护提供可靠的端到端
(End-to-End)
服务,它屏蔽了下层的数据通信细节,让用户及应用程序不需要考虑实际的通信方法。
5)、会话层(SessionLayer):主要负责两个会话进程之间的通信,即两
个会话层实体之间的信息交换,管理数据的交换。
6)、表示层(PresentationLayer):处理通信信号的表示方法,进行不同
的格式之间的翻译,并负责数据的加密解密,数据的压缩与恢复。
7)、应用层(ApplicationLayer):保持应用程序之间建立连接所需要的
数据记录,为用户服务。
在工作中,每一层会给上一层传输来的数据加上一个信息头(header),
然后向下层发出,然后通过物理介质传输到对方主机,对方主机每一层再对数
据进行处理,把信息头取掉,最后还原成实际的数据。本质上,主机的通信是
层与层之间的通信,而在物理上是从上向下最后通过物理信道到对方主机再从
下向上传输。
TCP/IP协议在实际应用中,最重要的是TCP/IP
(TransportControlProtocol/InternetProtocol)协议,它是目前最流行的商
业化的协议,相对于OSI,它是当前的工业标准或“事实的标准”,在1974年由
Kahn提出的。它分为四个层次(从高到低):应用层(与OSI的应用层对应),
传输层(与OSI的传输层对应),互联层(与OSI的网络层对应),主机-网络层
(与OSI的数据链路层和物理层对应)。
7.2 客户机与服务器
TCP/IP允许程序员在两个应用程序之间建立通信并来回传递数据,提供一种对
等通信,这种对等应用程序可以在同一台机器上,也可以在不同的机器上运行。尽
管TCP/IP指明了数据是如何在一对正在通信的应用程序间传递的,但是他并没有规
定对等的应用程序在什么时间进行交互以及为什么要进行交互,也没有规定程序员
在一个分布式环境下应该如何组织这些应用程序。实践中,有一种组织的方法在使
用TCP/IP中占据着主要地位,现在网络上的绝大多数的通信应用程序都使用这种机
制。
客户机/服务器模式要求每个应用程序应有两部分组成:一个部分负责启动通
信,另一个部分负责对他进行应答。他们通常运行在不同的主机上,分别被称为客
户机和服务器。服务器是指能在网络上可提供服务的任何程序;客户机是指用户为
了得到某种服务所需要运行的应用程序。一个服务器接受网络上客户机的请求,完
成服务后将结果返回给客户机。


发布评论