Berkeley套接字

    Berkeley套接字应用程序接口(也作BSD套接字应用程序接口)包括了一个用C语言写成的应用程序开发库,主要用于实现进程间通讯的功能,在计算机网络通讯方面被广泛使用。

    过程如下:

   

原语

含义

SOCKET

创建一个新的通信端点

BIND

将一个本地地址关联到一个套接字上

LISTEN

宣布其愿意接受连接,给出队列大小

ACCEPT

阻塞调用方,直到有人企图连接上

CONNECT

主动地尝试建立一个连接

SEND

在指定的连接上发送数据

RECV

从指定的连接中接收数据

CLOSE

释放指定的连接

 

    一个本地的应用程序和几个远程应用程序利用面向连接的传输层服务完成通信的操作过程如下:

    建立连接本地应用程序A(提供服务方)

    调用socket创建一个套接字S1,并在传输层实体中分配表空间,返回一个文件描述符,用于以后调用中使用S1。

    调用bind将某地址赋予S1,使得远程应用程序能访问本地应用程序A。

    调用listen分配数据空间,以便存储多个用户的连接建立请求。

    调用accept将本地应用程序A阻塞起来,等待接收客户程序发来的连接请求。

    当传输层实体接收到建立连接的TPDU时,创建一个和S1相同属性的套接字S2并返回其文件描述符。本地程序A创建一个子进程A-1处理此次连接,然后继续等待发往S1的请求。

    远程应用程序(主动建立连接方)调用socket创建一个套接字S,并在传输层实体中分配表空间,返回一个文件描述符用于在以后的调用中使用该套接字S。

    调用connect阻塞应用程序,传输层实体开始建立连接,当建立完成时,取消阻塞。

    数据传输:双方使用sendreceive完成数据的全双工发送。如果SEND和RECIEVE调用不要求特殊选项的话,服务器或者客户也可以使用标准的UNIX系统调用中的READWRITE

    close原语单独释放连接。

 

文章出处:http://old.blog.edu.cn/user1/19546/archives/2005/157064.shtml

 

一. Berkeley Socket实现TCP和UDP协议的流程

1. 面 向连接的TCP

2. 无连接的UDP

 

二. Berkeley套接字的一些基本知识

1. 基本结构

 

2. 基本转换函数

2.1 网络字节顺序

2.2 有关的转换函数

    在struct sockaddr_in中的sin_addr和sin_port他们的字节顺序都是网络字节顺序,而sin_family却不是网络字节顺序,为什么呢?

    这个是因为sin_addr和sin_port是从IP和UDP协议层取出来的数据,而在IP和UDP协议层,是直接和网络相关的,所以,它们必须使用网络字节序。然而,sin_family域只是内核用来判断struct sockaddr_in是存储的什么类型的数据,并且,sin_family永远也不会被发送到网络上,所以可以使用主机字节序来存储。

2.3 IP地址转换

    很幸运,Linux系统提供很多用于转换IP地址的函数,使你不必自己再写出一段费力不讨好的子程序来吃力的变换IP。首先,让我们假设你有一个struct sockaddr_in ina,并且你的IP是166.111.69.52,你想把你的IP存储到ina中,可以使用函数:inet_addr(),它能够把一个用数字和点表示的IP地址,转换成一个无符号长整型

你可以像下面这样使用它:

ina.sin_addr.s_addr = inet_addr("166.111.69.52");

注意:inet_addr()返回的地址已经是网络字节顺序了,你没有必要再去掉用htonl()函数

* inet_ntoa()使用strcut in_addr作为一个参数,不是一个长整型值。

* inet_ntoa()返回一个字符指针,它指向一个定义在函数inet_ntoa()中的static类型字符串。

 

3. 基本套接字调用

    Linux支持伯克利(BSD)风格的套接字编程。它同时支持面向连接和无连接类型的套接字。在面向连接的通讯中,服务器和客户机在交换数据之前要先建立一个连接。在无连接通讯中数据被作为信息的一部分被交换。无论哪一种方式,服务器总是最先启动,把自己绑定(Banding)在一个套接字上然后侦听信息。服务器究竟怎样试图去侦听就得依靠你编程所设定的连接类型了

3.1 socket()函数

3.2 bind()函数

    最后注意有关bind()的是:有时候你并不一定要调用bind()来建立网络连接。比如你只是想连接到一个远程主机上面进行通讯,你并不在乎究竟是用自己机器上的哪个端口进行通讯(比如 Telnet),那么你可以简单的直接调用connet()函数,connect()将自动寻找本地机器上的一个未使用的端口,然后调用bind()来将其socket绑定到那个端口上

3.3 connect()函数

    再次强调,一定要检测connect()的返回值:如果发生了错误(比如无法连接到远程主机,或是远程主机的指定端口无法进行连接等)它将会返回错误值-1。全局变量errno将会存储错误代码。基本上,我们并不在乎我们本地用什么端口来通讯,是不是?我们在乎的是我们连到哪台主机的哪个端口上。Linux内核自动为我们选择了一个没有被使用过的本地端口

3.4 listen()函数

    listen()函数是等待别人来连接,进行系统侦听请求的函数。当有人连接你的时候,需要做两步:通过listen()函数等待连接请求,然后使用accept()函数来处理。

    如果你想在一个端口上接受外来连接请求的话,那么函数的调用顺序为:

    socket();

    bind();

    listen();

    /* 在这里调用accept()函数 */

    ......

3.5 accept()函数

    如果accept()失败的话,accept()函数会返回一个-1来表明调用失败,同时全局变量errno将会存储错误代码。

    面向连接的通信中客户机要做如下一些事:

    调用一个socket()函数创建一个套接字;

    调用一个connect()函数试图连接服务;

    如果连接成功调用,wirte()函数请求数据,调用read()函数接收引入的应答。

3.6 send()、recv()函数

    这两个函数是最基本的。

    send()函数在调用后会返回它真正发送的数据的长度。

    注意:send()所发送的数据可能少于你给它的参数所制定的长度!

    因为,如果你给send()的参数中包含的数据的长度远远大于send()所能一次发送的数据,则send()函数只能发送它所能发送的最大数据长度,然后它相信你会把剩下的数据再次调用它来进行第二次发送。所以,记住,如果send()函数的返回值小于len的话,则你需要再次发送剩下的数据。幸运的是,如果包足够小(小于IK),那么send()一般都会一次发送光的。

3.7 sendto()、recvfrom()函数

    这两个函数是进行无连接的UDP通讯时使用的使用这两个函数,则数据会在没有建立过任何连接的网络上传输因为数据报套接字无法对远程主机进行连接,想想我们在发送数据前需要知道些什么呢

    PS: 取得远程主机的IP地址和端口!

    注意:如果你使用connect()连接到了一个数据报套接字的服务器程序上,那么你就可以使用send()和recv()函数来传输你的数据,不要以为你在使用一个流式的套接字,你所使用的仍然是一个使用者数据报的套接字,只不过套接字界面在send()和recv()的时候自动帮助你加上了目标地址,目标端口的信息。

文章出处:http://shihaiyang.javaeye.com/blog/503554

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值