网络进程之间的通信时通过套接字来实现的,套接字是通信端点的抽象,与应用程序使用文件描述符是一样的,本文讲解一下基于UDP的服务器程序的编写,具体步骤如下:
1、 创建套接字。
创建套接字需要调用socket函数,socket函数在<sys/socket.h>文件中,函数原型为:
Int socket (int domain, int type, intprotocol);
(1)参数domain确定通信的特性,在IPV4因特网域中通信, domain为AF_INET;
(2)参数type为套接字类型,POSIX.1 定义的套接字类型有以下4种,
SOCK_DGRAM:长度固定无连接的不可靠报文传递;
SOCK_RAW:IP协议的数据报接口;
SOCK_SEQPACKET:长度固定,有序,可靠的面向连接报文传递;
SOCK_STREAM:有序,可靠,双向的面向连接字节流。
UDP协议用的是SOCK_DGRAM类型,TCP/IP协议用的是SOCK_STREAM类型。
(3)参数protocol通常是零,表示按照给定的域和套接字类型自动选择默认协议。
2、寻址。
在使用套接字通信之前,需要知道如何确定一个目标通信进程,进程的标识有两个部分:计算机的网络地址可以帮助标识网路上想与之通信的计算机,而服务可以帮助标识计算机上特定的进程。
(1)地址格式
地址标识了特定通信域中的套接字端点,地址格式与特定的通信域相关,为使不同格式的地址能够传入道套接字函数,地址被强制转换成通用的地址结构sockaddr表示:
Structsocketaddr {
Sa_family_t sa_family;
Char sa_data[];
……
};
在Linux中,一般使用sockaddr_in结构体表示,
Structsockaddr_in {
Sa_family_t sa_family;
In_port _t sin_port;
Struct in_addr sin_addr;
Unsigned charsin_zero[8];
};
Sa_family表示地址族,在IPV4协议下为AF_INET,sin_port表示端口号,sin_addr表示网络地址,即目标地址,sin_zero[8]为保留字,给in_addr赋值最简单与最常用的方法是使用inet_addr函数,它可以将一个代表IP地址的字符串转化为in_addr类型,例如:
Addrto.sin_addr.s_addr = inet_addr(“192.168.0.1”);
反函数为inet_ntoa函数,将网络地址转化为IP 字符串表示的IP地址。
(2)将套接字与地址绑定。
与客户端的套接字关联的地址没有太大意义,可以让系统选一个默认的地址,然而,对于服务器来说,需要给一个接收客户端请求的套接字绑定一个地址,可以用bind函数将地址绑定到一个套接字。
Int bind(int sockfd, const struct sockaddr*addr, socklen_t len);
Sockfd为套接字,addr为地址,len为地址长度。
3、 数据传输。
设置好了套接字之后,就可以进行数据传输了,对于无连接的套接字,我们可以使用sendto函数和recvfrom函数来发送和接收数据。
当有多个socket在服务器与客户端之间通信时,我们需要用到I/O多路转接的知识,select函数可以完成I/O多路转接,I/O多路转接是先构造一张有关描述符的列表,然后调用select函数直到这些描述符中的一个已准备好进行I/O时,该函数才返回,函数返回时,它告诉进程哪些描述符已准备好可以进行I/O。