相关结构体:
struct sockaddr_in { sa_family_t sin_family; /* address family: AF_INET */ in_port_t sin_port; /* port in network byte order */ struct in_addr sin_addr; /* internet address */ }; /* Internet address. */ struct in_addr { uint32_t s_addr; /* address in network byte order */ }; sin_family is always set to AF_INET. This is required; |
服务器端流程
1.创建socket
2.绑定socket到端口
3.进入监听状态
4.等待客户端到来
5.和客户端通信,进行网络任务
6.断开连接
1.创建socket
#include <sys/types.h>
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
domain:通讯使用的协议簇,一般为AF_INET(IPV4)或AF_INET6(IPV6)
type:套接字类型,一般为SOCK_STREAM(TCP连接)或SOCK_DGRAM(UDP连接)
protocol:使用的协议,一般来说确定的协议簇只使用一种协议,所以此值一般是0.
返回0表示成功,-1表示失败,具体的错误代码在errno里面。
例: int server_sockfd=socket(AF_INET,SOCK_STREAM,0); if (server_sockfd == -1){ //处理错误 return -1; } |
2.绑定端口:
#include <sys/types.h>
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *addr,
socklen_t addrlen);
sockfd:服务端套接字句柄
addr:其实现在都使用结构体sockaddr_in代替sockaddr了,这个结构体填装了服务器要绑定的端口号,接受的IP范围,使用的协议信息。
addrlen:结构体的大小。
返回0表示成功,-1表示失败,具体的错误代码在errno里面。
例: struct sockaddr_in server_addr; memset(&server_addr,0,sizeof(server_addr)); server_addr.sin_family=AF_INET; server_addr.sin_addr.s_addr=htonl(INADDR_ANY); server_addr.sin_port=htons(SOCKET_PORT); if(bind(server_sockfd,(struct sockaddr*)&server_addr,sizeof(server_addr)) == -1){ //处理错误 return -1; } |
3.监听:
#include <sys/types.h>
#include <sys/socket.h>
int listen(int sockfd, int backlog);
sockfd:服务端套接字句柄。
backlog:当连接到来时,排队的最大数量。
返回0表示成功,-1表示失败,具体的错误代码在errno里面。
例: if(listen(g_server_sockfd,1) == -1){ //处理错误 return -1; } |
4.等待客户端:
#include <sys/types.h>
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
sockfd:服务端套接字句柄。
addr:客户端信息,一般是sockaddr_in结构体。
addrlen:客户端信息长度。
返回一个客户端socket句柄表示成功,-1表示失败,具体的错误代码在errno里面。
例: int client_sockfd=-1; struct sockaddr_in client_addr; if((client_sockfd=accept(g_server_sockfd,(struct sockaddr*)&client_addr,&addr_len))== -1) //处理错误 break; } |
5.通信:
接收消息:
#include <sys/types.h>
#include <sys/socket.h>
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
struct sockaddr *src_addr, socklen_t *addrlen);
ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
其中recv一般只用于TCP连接。
返回0表示对方关闭了连接,返回-1表示有错误发生,正常时返回接收到的数据大小。
这个函数默认是阻塞的,可以改变socket的属性来设置非阻塞或超时时间。
例: char data_buffer[256]; while((data_len=recv(client_sockfd,data_buffer,256,0))>0){ //处理数据 } |
发送消息:
#include <sys/types.h>
#include <sys/socket.h>
ssize_t send(int sockfd, const void *buf, size_t len, 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 sendmsg(int sockfd, const struct msghdr *msg, int flags);
跟接收消息差不多。
6.断开连接:
#include <unistd.h>
int close(int fd);
或者:
#include <sys/socket.h>
int shutdown(int sockfd, int how);
how:SHUT_RD,SHUT_WR,SHUT_RDWR
客户端流程
1.创建socket:
和服务端一样。
2.连接服务器:
#include <sys/types.h>
#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *addr,
socklen_t addrlen);
sockfd:客户端套接字句柄。
addr:填充了服务器的地址和端口号,协议等信息。
返回0表示成功,-1表示失败,具体的错误代码在errno里面。
3.通信:
和服务端一样。
4.关闭:
和服务端一样。