第二节 socket相关函数
socket编程函数主要有7个,3个结构体;
函数为:socket()、bind()、connect()、listen()、accept()、send()、recv()
结构体:sockaddr_in、in_addr、sockaddr
socket通信流程:
服务器
|
|
socket() //创建套接字
|
|
bind() //socket绑定端口
|
|
listen()//监听 客户机
| |
| |
accept() //接收信息 connet()
| |
| |
read() //读取接收的信息 <----------------- write()//发送信息
| |
| |
write()//发送信息------------------------->read()//读取接收到的信息
2.1 socket() 函数
作用:创建套接字
#include <sys/socket.h>
int socket(int af, int type, int protocol);
af:IP地址的类型
AF_INET : IPv4
AF_INET6: IPV6
type:数据传输方式
SOCK_STREAM:面向连接的数据传输方式
SOCK_DGRAM:无连接的数据传输方式
protocol:传输协议
IPPROTO_TCP:TCP传输协议
IPPTOTO_UDP:UDP传输协议
返回值 成功:0 失败:-1
示例:
int tcp_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
int tcp_socket = socket(AF_INET, SOCK_STREAM, 0);
2.2 bind()函数
作用:地址绑定,将套接字与地址关联
#include <sys/types.h>
#include <sys/socket.h>
int bind(int sockfd, struct sockaddr *addr, socklen_t addrlen);
sockfd:socket文件描述符
addr:sockaddr 结构体变量的指针
addrlen:addr 变量的大小
返回值:成功:0 、 失败:-1
示例代码:
//创建套接字
int sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
//创建sockaddr_in结构体变量
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr)); //每个字节都用0填充
serv_addr.sin_family = AF_INET; //使用IPv4地址
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); //具体的IP地址
serv_addr.sin_port = htons(1234); //端口
//将套接字和IP、端口绑定
bind(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
2.3 connect()函数
作用:建立连接,创建与指定外部端口的连接
#include <sys/types.h>
#include <sys/socket.h>
int connect(int sockfd, struct sockaddr *serv_addr, socklen_t addrlen);
sockfd:socket文件描述符
addr:sockaddr 结构体变量的指针
addrlen:addr 变量的大小
返回值:成功0;失败-1
示例
connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr))
2.4 listen()函数
作用:让套接字进入被动监听状态,使得一个进程可以接受其它进程的请求,从而成为一个服务器进程;
#include <sys/types.h>
#include <sys/socket.h>
int listen(int sockfd, int backlog);
sockfd:被监听的套接字的标识符;
backlog:请求队列的最大长度(能存放多少个客户端请求)
返回值:成功0;失败-1;
示例代码:
#define BACKLOG 10
...
if (listen(sockfd, BACKLOG) == -1) {
perror("listen出错!");
exit(1);
}
2.5 accept() 函数
作用:在一个套接口接受一个连接,当套接字处于监听状态时,可以通过 accept() 函数来接收客户端请求
accept() 会阻塞程序执行(后面代码不能被执行),直到有新的请求到来;
#include<sys/socket.h>
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
sockfd:服务器端套接字的标识符
addr:sockaddr 结构体变量的指针
addrlen:addr 变量的大小
返回值:成功:返回接收到的套接字的描述符;失败:-1
示例代码:
struct sockaddr_in cli_addr;
sin_size = sizeof(cli_addr);
accept(sockfd, (struct sockaddr *)&cli_addr, &sin_size));
2.6 send() 函数
作用:发送数据将数据由指定的socket 传给对方主机
#include <sys/types.h>
#include <sys/socket.h>
int send(int s, const void * msg, int len, unsigned int falgs);
s:以建立好连接的socket标识符
msg:发送的消息内容
len:发送内容的长度
falgs:一般设为0
返回值:成功返回实际传送出去的字符数; 失败:-1
2.7 recv() 函数
作用:接收数据
#include <sys/types.h>
#include <sys/socket.h>
int recv(int sock, void *buf, int len, unsigned int flags);
sock:接收端套接字描述符
buf:指定缓冲区,存放接收到的数据
len:缓冲区的长度
flags:一般设为0
返回值:成功返回收到的字符数 失败:-1
示例:
#define MAXDATASIZE 100 /*每次最大数据传输量 */
recv(sockfd, buf, MAXDATASIZE, 0))
2.8 sockaddr_in 结构体
struct sockaddr_in{
sa_family_t sin_family; //地址族,也就是地址类型
uint16_t sin_port; //16位的端口号
struct in_addr sin_addr; //32位IP地址
char sin_zero[8]; //不使用,一般用0填充
};
端口号需要用 htons() 函数转换;
2.9 in_addr 结构体
#include <netinet/in.h>
struct in_addr{
in_addr_t s_addr; //32位的IP地址
};
2.10 sockaddr 结构体
struct sockaddr{
sa_family_t sin_family; //地址族,也就是地址类型
char sa_data[14]; //IP地址和端口号
};
sockaddr 是一种通用的结构体,可以用来保存多种类型的IP地址和端口号,而 sockaddr_in 是专门用来保存 IPv4 地址的结构体