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中占据着主要地位,现在网络上的绝大多数的通信应用程序都使用这种机

制。

客户机/服务器模式要求每个应用程序应有两部分组成:一个部分负责启动通

信,另一个部分负责对他进行应答。他们通常运行在不同的主机上,分别被称为客

户机和服务器。服务器是指能在网络上可提供服务的任何程序;客户机是指用户为

了得到某种服务所需要运行的应用程序。一个服务器接受网络上客户机的请求,完

成服务后将结果返回给客户机。