socket(协议方案,数据流/快形式,附加协议)函数介绍:
#include
#include
int socket(int domain, int type, int protocol);//设置网络协议创建一个句柄,成功调用返回套接字描述符,失败返回错误码
domain
参数指明所使用的协议族,通常为AF_INET,表示互联网协议族(TCP/IP协议族);通信协议族在文件sys/socket.h中定义。
AF_INET | IPv4因特网域 |
---|---|
AF_INET6 | IPv6因特网域 |
AF_UNIX | Unix域 |
AF_ROUTE | 路由套接字 |
AF_KEY | 密钥套接字 |
AF_UNSPEC | 未指定 |
type
参数用于设置套接字通信的类型,主要有SOCKET_STREAM
(流式套接字)、SOCK——DGRAM
(数据包套接字)等。
SOCK_STREAM | Tcp连接,提供序列化的、可靠的、双向连接的字节流。支持带外数据传输 |
---|---|
SOCK_DGRAM | 支持UDP连接(无连接状态的消息) |
SOCK_SEQPACKET | 序列化包,提供一个序列化的、可靠的、双向的基本连接的数据传输通道,数据长度定常。每次调用读系统调用时数据需要将全部数据读出 |
SOCK_RAW | RAW类型,提供原始网络协议访问 |
SOCK_RDM | 提供可靠的数据报文,不过可能数据会有乱序 |
SOCK_PACKET | 这是一个专用类型,不能在通用程序中使用 |
参数protocol
用于制定某个协议的特定类型,即type
类型中的某个类型。通常某协议中只有一种特定类型,这样protocol
参数仅能设置为0;但是有些协议有多种特定的类型,就需要设置这个参数来选择特定的类型。
IPPROTO_TCP | tcp传输协议 |
IPPROTO_UDP | udp传输协议 |
IPPROTO_SCIP | sctp传输协议 |
IPPROTO_TIPC | tipc传输协议 |
注:
~类型为SOCK_STREAM
的套接字表示一个双向的字节流,与管道类似。流式的套接字在进行数据收发之前必须已经连接,连接使用connect
()函数进行。一旦连接,可以使用read
()或者write
()函数进行数据的传输。流式通信方式保证数据不会丢失或者重复接收,当数据在一段时间内仍然没有接受完毕,可以将这个客户端认为已经死掉。
~SOCK_DGRAM
和SOCK_RAW
这个两种套接字可以使用函数sendto
()来发送数据,使用recvfrom
()函数接受数据,recvfrom
()接受来自制定IP地址的发送方的数据。
~SOCK_PACKET
是一种专用的数据包,它直接从设备驱动接受数据。
bind
(绑定地址)函数:
通过socket
调用创建的套接字必须经过命名(绑定地址)后才能使用。bind系统调用把addr
中的地址分配给与描述符socket关联的未命名套接字,地址结构的长度由addr_len
指定。 addr
和addr_len
因地址族(AF_UNIX
、AF_INET
等)的不同而不同,bind调用时需要将指向特定地址结构的指针转化为指向通用地址的指针,即(struct sockaddr *)。
#include
int bind( int sockfd, const struct sockaddr *addr, socklen_t addrlen);
//参数1:socket描述符
//参数2:一个包含主机ip地址和端口号等信息的sockaddr类型的指针。
struct scokaddr{
unsigned short as_family;//协议族
char as_data[14];//ip+端口
};
同等替换:
struct sockaddr_in{
sa_family_t sin_family;//协议族
in_port_t sin_port;//端口号
struct in_addr sinaddr;//ip地址结构体
unsigned char sin_zero[8];//填充 没有实际意义,只是为了跟socketaddr结构在内存中对齐,这样才可以相互转换
}
//参数3:参数2长度用sizeof()直接获取
listen函数(服务端监听客户端连接请求)
int listen( int sockfd, int backlog);
//sockfd:用于标识一个已捆绑未连接套接口的描述字。
//backlog:等待连接队列的最大长度。
accept函数(接收客户端的ip和端口等信息)
int accept( int sockfd, struct sockaddr *addr, socklen_t *addrlen);
/*第一个参数为服务器的socket描述字,
第二个参数为指向struct sockaddr *的指针,用于返回客户端的协议地址,
第三个参数为协议地址的长度。如果accpet成功,那么其返回值是由内核自动生成的一个全新的描述字,代表与返回客户的TCP连接。*/
客户端connect()函数
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
/*第一个参数即为客户端的socket描述字,
第二参数为服务器的socket地址,
第三个参数为socket地址的长度。客户端通过调用connect函数来建立与TCP服务器的连接。*/
对所创建的套接字进行读写操作时可以用到以下函数:
接收函数 | 发送函数 |
---|---|
read( ) | write( ) |
recv( ) | send( ) |
readv( ) | writev() |
recvmsg( ) | sendmsg( ) |
recvfrom( ) | sendto( ) |
函数原型如下:
ssize_t read(int fd, void *buf, size_t count);
ssize_t write(int fd, const void *buf, size_t count);
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
ssize_t readv(int fd, const struct iovec *iov, int iovcnt);
ssize_t writev(int fd, const struct iovec *iov, int iovcnt);
ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
ssize_t sendto(int sockfd,
const void *buf,
size_t len,
int flags,
const struct sockaddr *dest_addr,
socklen_t addrlen);
ssize_t recvfrom(int sockfd,
void *buf,
size_t len,
int flags,
struct sockaddr *src_addr,
socklen_t *addrlen);
//具体参数可以通过man手册查看
close函数:当所有的数据操作结束以后,你可以调用close()函数来释放该socket,从而停止在该socket上的任何数据操作
close原型:
int close(int fd);//参数为套接字描述符
注:如果有多个进程共享一个套接字,close每被调用一次,计数减1,直到计数为0时,也就是所用进程都调用了close,套接字将被释放。
除了上面的一些函数以外还有:
服务器要告诉客户端自己的端口和ip等信息就需要以下的字节序转换和IP地址转换函数
字节序转换函数(将端口号转换为网络字节序):
#include
uint32_t htonl(uint32_t hostlong);//返回网络字节序的值
uint16_t htons(uint16_t hostshort);//返回网络字节序的值
uint32_t ntohl(uint32_t netlong);//返回主机字节序的值
uint16_t ntohs(uint16_t netshort);//返回主机字节序的值
地址转换函数
#include
#include
#include
int inet_aton(const char *cp, struct in_addr *inp);//把字符串形式的IP地址转换为网络能识别的格式并且存储在一个结构体指针里面
char *inet_ntoa(struct in_addr in);//把网络格式的IP地址转换为字符串
~socket字节处理函数
Socket地址是多字节数据,不是以空字符结尾的,这和C语言中的字符串是不同的。Linux提供了两组函数来处理多字节数据,一组以b(byte)开头,是和BSD系统兼容的函数,另一组以mem(内存)开头,是ANSI C提供的函数。
以b开头的函数有:
(1) void bzero(void * s,int n)
:将参数s指定的内存的前n个字节设置为0,通常它用来将套接字地址清0。
(2) void bcopy(const void * src,void * dest,int n)
:从参数src指定的内存区域拷贝指定数目的字节内容到参数dest指定的内存区域。
(3) int bcmp(const void * s1,const void * s2,int n)
:比较参数s1指定的内存区域和参数s2指定的内存区域的前n个字节内容,如果相同则返回0,否则返回非0。
注:以上函数的原型定义在strings.h中。
以mem开头的函数有:
(1) void * memset(void * s,int c,size_t n)
:将参数s指定的内存区域的前n个字节设置为参数c的内容。
(2) void * memcpy(void * dest,const void * src,size_t n)
:功能同bcopy(),区别:函数bcopy()能处理参数src和参数dest所指定的区域有重叠的情况,memcpy()则不能。
(4) int memcmp(const void * s1,const void * s2,size_t n)
:比较参数s1和参数s2指定区域的前n个字节内容,如果相同则返回0,否则返回非0。
注:以上函数的原型定义在