在Linux下开发网络程序和Window下非常的类似,都是基于Socket的编程, Socket接口是TCP/IP网络的API。Socket数据传输是一种特殊的I/O,具有一个类似于打开文件的函数调用socket(),返回一个整型的Socket描述符,随后的连接建立、数据传输等都是通过该Socket实现。
1 Socket 的分类:
流式套接字(SOCK_STREAM): 面向连接的,对应于TCP服务应用
数据报式套接字(SOCK_DGRAM) :无连接的,对应于UDP服务应用
原始套接字(SOCK_RAW):低于传输层的低级协议或物理网络提供的套接字类型,可访问内部网络接口,如接收和发送ICMP报。
2 Socket的建立:
调用socket函数,返回一个类似于文件描述符的句柄,其原型为:
int socket(int domain,int type,int protocol);
domain指明所使用的协议族,通常为AF_INET,表示互联网协议族(TCP/IP协议族);
type参数指定socket的类型;
protocol通常赋值“0”,表示默认为TCP/IP协议
socket()调用返回一个整型socket描述符,在以后的调用中使用。
3 Socket 的配置:
通过socket调用返回一个socket描述符后,在使用socket进行网络传输以前,必须配置该socket。面向连接的socket客户端通过调用Connect函数在socket数据结构中保存本地和远端信息
无连接socket的客户端和服务端以及面向连接socket的服务端通过调用bind函数来配置本地信息。
4 、INET 地址协议结构:
struct sockaddr_in {
short int sin_family;
unsigned short int sin_port;
struct in_addr sin_addr;
unsigned char sin_zero[8];
};
指向sockaddr_in 的指针和指向sockaddr的指针可以相互转换,这意味着如果一个函数所需参数类型是sockaddr时,你可以在函数调用的时候将一个指向sockaddr_in的指针转换为指向sockaddr的指针;或者相反。
5 TCP编程
服务器端步骤:
Ø 创建套接字 socket()
Ø 绑定套接字 bind() ------> listen()
Ø 设置套接字为监听模式,进入被动接受连接请求状态
Ø 接受请求,建立连接 recv()
Ø 读写数据 send()
Ø 终止连接 close()
Socket()--->Bind()--->Listen()--->Accept()--->Recv()--->Send--->Close()
int socket(int domain,int type,int protocol);
domain指明所使用的协议族,通常为AF_INET,表示互联网协议族(TCP/IP协议族);
type参数指定socket的类型;
protocol通常赋值“0”,表示默认为TCP/IP协议
socket()调用返回一个整型socket描述符,在以后的调用中使用
bind函数将socket与本机上的一个端口相关联,随后可以在该端口监听服务请求。
bind函数原型为 :
int bind(int sockfd, struct sockaddr *my_addr, int addrlen);
sockfd:是调用socket函数返回的socket描述符
my_addr:是一个指向包含有本机IP地址及端口号等信息的sockaddr类型的指针
addrlen:代表my_addr指向的地址结构的长度,可设置为 sizeof(struct sockaddr)
int listen(int sockfd, int backlog);
sockfd:Socket系统调用返回的socket 描述符
backlog:指定在请求队列中允许的最大请求数,进入的连接请求将在队列中等待accept()它们。Backlog对队列中等待服务的请求的数目进行了限制,大多数系统缺省值为20。如果一个服务请求到来时,输入队列已满,该socket将拒绝连接请求,客户将收到一个出错信息.
int accept(int sockfd, void *addr, int *addrlen);
sockfd:被监听的socket描述符
addr:一个指向sockaddr_in变量的指针,该变量用来存放提出连接请求服务的主机的信息(某台主机从某个端口发出该请求)
addrlen:一个指向值为sizeof(struct sockaddr_in)的整型指针变量.
int connect(int sockfd, struct sockaddr *serv_addr,int addrlen);
sockfd是socket函数返回的socket描述符
serv_addr是包含远端主机IP地址和端口号的指针
addrlen是远端地址结构的长度.
客户端步骤:
Ø 创建套接字
Ø 与远程服务程序连接
Ø 读写数据
Ø 终止连接
Socket()--->Connect()--->Send()--->Recv()--->Close()
我们在开发网络程序的时候需要一些字节序的问题,在网络上发送的数据是遵循网络字节序,当数据传送到我们主机上时,需要将网络字节转换成主机字节序。
字节顺序转换函数:
htonl():把32位值从主机字节顺序转换成网络字节顺序
htons():把16位值从主机字节顺序转换成网络字节顺序
ntohl():把32位值从网络字节顺序转换成主机字节顺序
ntohs():把16位值从网络字节顺序转换成主机字节顺序
注意:在使用bind函数时需要将sin_port和sin_addr转换成为网络字节顺序
6 UDP 编程:
服务器端实现步骤:
Ø 建立UDP套接字;
Ø 绑定套接字到特定地址;
Ø 等待并接收客户端信息;
Ø 处理客户端请求;
Ø 发信息回客户端;
Ø 关闭套接字
Socket()--->Bind()--->Recvfrom()/Sendto()--->Close()
客户端实现步骤:
Ø 建立UDP套接字;
Ø 发送信息给服务器;
Ø 接收来自服务器的信息;
Ø 关闭套接字
Socket()--->Sendto()/Recvfrom()--->Close()
sendto()函数原型为:
int sendto(int sockfd, const void *msg,int len,unsigned int flags,const struct sockaddr *to, int tolen);
flags:调用方式标志,通常取0
to:目地机的IP地址和端口号信息
tolen:赋值为sizeof (struct sockaddr)
返回值:返回实际发送的数据字节长度或在出现发送错误时返回-1
recvfrom()函数原型为:
int recvfrom( int sockfd, void *buf, int len, unsigned int flags, struct sockaddr *from,int *fromlen);
flags:调用操作方式,通常取0
from是一个struct sockaddr类型的变量,该变量保存源机的IP地址及端口号
fromlen常置为sizeof (struct sockaddr)。当recvfrom()返回时,
fromlen包含实际存入from中的数据字节数
返回值:返回接收到的字节数或当出现错误时返回-1,并置相应的errno