Socket编程基本函数
Socket通信创建流程图 学课的时候写了个小demo,看完下面的函数可以看看demo中的实例
sokcet 函数
功能简述:socket() 打开一个网络通讯端口。类似文件操作open()返回一个文件操作符。
如果socket()调用出错返回-1。
#include <sys/types.h>
#include <sys/socket.h>
int socket(int domain,int type,int protocol);
domain:AF_INET用来产生socket的协议,使用TCP或UDP来传输,用IPv4的地址。
AF_INET6 行为与IPv4类似,使用IPv6地址
AF_UNIX本地协议,使用在Unix和Linux系统上。一般当客户端和服务器在同一台及其上的时候使用
type:
SOCK_STRAM这个协议是按照顺序的、可靠的、数据完整的基于字节流的连接。是使用最多的
SOCK_DGRAM这个协议是无连接的、固定长度的传输调用。该协议是不可靠的,使用UDP来进行连接
SOCK_SEQOACKET该协议是双线路的、可靠的连接,发送固定长度的数据包进行传输。必须把包传输完整才能进行读取。
SOCK_RAW socket类型提供单一的网络访问,这个socket类型使用ICMP公共协议。(ping、traceroute使用该协议)
SOCK_RDM这个类型是很少使用的,在大部分操作系统中未实现,提供给数据链路层使用,不保证数据包的顺序
protocol:
传0 表示默认协议
返回值
成功:返回指向新创建的socket文件操作符。
失败:返回-1,设置errno
对于IPv4,domaindomain参数指定为AF_INET。
对于TCP协议,type参数指定为SOCK_STREAM,表示面向流的传输协议。
对于UDP协议,type参数指定为SOCK_DGRAM,表示面向数据包的传输协议。
bind函数
功能简述:绑定一个固定的网络地址和端口号接收客户端发起的连接
#include <sys/types.h>
#include <sys/socket.h>
int bind(int sockfd,const struct sockaddr* addr,socklen_t addrlen);
sockfd:创建的socket文件描述符。即文件操作符。
addr:构造出IP地址加端口号
addrlen:sizeof(addr)长度
成功返回0
失败返回-1 设置errno
bind()的作用是将sockfd和addr绑定在一起。使sockfd这个文件操作符监听addr所描述的地址和端口号。struct sockaddr* 是一个通用的指针类型。addr参数可以接受多种协议的sockaddr结构体,而他们的长度不相同,所以需要第三个参数addrlen指定结构体的长度
listen 函数
listen声明sockfd处于监听状态,并且规定最多多少个连接处于待连接状态。如果超过规定数量连接请求就忽略。
#include <sys/types.h>
#include <sys/socket.h>
int listen(int sockfd,int backlog);
sockfd:
socket文件操作符
backlog:
在Linux系统中,指排队等待建立3次握手队列的长度
使用说明:当客户端发起来连接而服务器来不急处理。尚未被接收的客户端处于待连接状态,如果收到超过一定数量级的连接等待就忽略。
accept 函数
使用场景:三次握手是在客户端Connect、服务端Listen后,三次握手完成后服务器调用accept()接受连接。如果没有连接请求,就阻塞等待直到有客户端连接。
#include <sys/types.h>
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
sockdf:
socket文件描述符
addr:
传出参数,返回链接客户端地址信息,含IP地址和端口号
addrlen:
传入传出参数(值-结果),传入sizeof(addr)大小,函数返回时返回真正接收到地址结构体的大小
返回值:
成功返回一个新的socket文件描述符,用于和客户端通信,失败返回-1,设置errno
connect函数
客户端调用connect函数连接服务器
#include <sys/types.h>
#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
sockdf:
socket文件描述符
addr:
传入参数,指定服务器端地址信息,含IP地址和端口号
addrlen:
传入参数,传入sizeof(addr)大小
返回值:
成功返回0,失败返回-1,设置errno
出错处理函数
函数执行出错打印出错信息
#include <errno.h>
#include <string.h>
char *strerror(int errnum);
errnum:
传入参数,错误编号的值,一般取 errno 的值
返回值:
错误原因
#include <stdio.h>
#include <errno.h>
void perror(const char *s);
s:
传入参数,自定义的描述
返回值:
无
向标准出错stderr 输出出错原因
相关结构
sockaddr结构
sockaddr 传递一个地址给函数(void *)。至于这个函数使用sockadd_in还是其他由地址族确定,然后函数强制转换为所需地址类型
struct sockaddr{
sa_family_t sa_family;
char sa_data[14];
};
struct sockaddr_in{
sa_family_t sin_family;
in_port_t sin_port;
struct in_addr sin_addr;
};
struct in_addr
{
uint32_t s_addr;
};
因为sock API早于ANSI C标准化。当时没有void * 类型。因此bind、accept函数的参数在传递之前需要强制转换。
struct sockaddr_in servaddr;
bind(listen_fd,(struct_sockaddr*)servaddr,sizeof(servaddr));
sockaddr_in使用实例:
struct sockaddr_in servaddr;
bzero(&servaddr,sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(6666);
首先将整个结构体清零,然后设置地址类型为AF_INET,网络地址为INADDR_ANY,这个宏表示本地的任意IP地址,因为服务器可能有多个网卡,每个网卡也可能绑定多个IP地址,这样设置可以在所有的IP地址上监听,直到与某个客户端建立了连接时才确定下来到底用哪个IP地址,端口号为6666。
字节序转换
网络数据流同样有大小端之分。发送主机通常将发送缓冲区中的数据按内存地址从高到低的顺序发出,接收主机把从网络接到的字节一次保存在接收缓冲区内,也是按内存地址从低到高的顺序保存。网络数据流的地址:先发出的数据是低地址,后发出的数据是高地址 TCP/IP协议规定:网络数据流采用大端字节序,及低地址高字节。 因为操作系统的不同设计,所以在通信过程中不同操作系统可能采用不同字节序。所以在通信前数据需要转换字节序。
#include <apra/inet.h>
uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);
IP转换函数:IP转换函数进行IP字节序的转换。
#include <apra/inet.h>
int inet_pton(int af,const char* src,void *dst);
const char* inet_ntop(int af,const void* src,char *dst,socklen_t size);
inet_pton 、inet_ntop不仅可以转换IPV4的inet_addr。还可以转换IPV6的in6_addr。 因此函数接口是 void* addrptr。
|