# 头文件
Windows下 #include < WinSock2.h > #pragma comment(lib,"ws2_32")
WSADATA wsaData; if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { std::cerr << "WSAStartup failed" << std::endl; return 1; }
Linux下 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> //sockaddr_in #include <arpa/inet.h> //inet_pton #include <unistd.h> // close()关闭socket
# 创建套接字
int soecket(int _domain, int _type, int _protocol)
- _domain 协议族 AF_INET IPV4 AF_INET6 IPV6 AF_LOCAL 本地通讯
- _type 数据类型 SOCK_RAW 原始套接字 SOCK_STREAM TCP/IP SOCK_DGRAM UDP/IP
- _protocol 协议类型 填0就好了,默认选择_type对应的协议
int fd = socket(AF_INET,SOCK_STERAM,0); if(fd < 0){ perror("socket"); }
# bind绑定 or connect连接
int bind(int _socket, const sockaddr* _addr, socklen_t _len) int connect(int _socket, const sockaddr* _addr, socklen_t _len)
struct sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htons(port); // Server addr.sin_addr.s_addr = INADDR_ANY; // Windows addr.sin_addr.S_un.S_addr = inet_addr("ip"); // Linux inet_pton(AF_INET,"IP",&addr.sin_addr.s_addr);// arpa/inet.h /* ------ */ bind(fd,(struct sockaddr*)&addr,sizeof(addr)); connect(fd,(struct sockaddr*)&addr,sizeof(addr));
# listen
int listen (int _socket, int _n)
- _socket使用哪个socket监听
- _n 队列长度
listen(fd,10); //只有服务端需要进行监听
# accept
int accept(int _socket, struct sockaddr* client_addr, socklen_t *addrlen) _socket 使用哪个套接字 client_addr接受到的客户端信息 *addrlen sizeof(struct sockaddr)
struct sockaddr_in clientAddr; sockLen_t len = sizeof(clientAddr); int clientfd = accept(fd,(struct sockaddr*)&clientAddr,&len); // 如果不需要客服端的信息的话 int clientfd = accept(fd,NULL,NULL);
# 发送数据
# send
ssize_t send(int _socket, const void* buff, size_t _n,int flag)
const char * msg = "Hello World"; send(fd,msg,sizeof(msg),0);
# sendto
sendto( _in int fd, _in const char far* buf, // 数据缓冲区 _in int len, // 缓冲区大小 _in int flags, // 一般填0 _in cosnt struct sockaddr far* to, // 发送的地址信息 _in int toLen // sizeof(sockaddr) )
# recv接收数据
ssize_t recv(int _socket, void *buff, size_t _n, int flag) 返回值: 0=连接关闭 >0 接收到的数据包大小 <0错误
char buf[1024]; recv(fd,buf,sizeof(buf),0);
# 关闭连接
int close(int _socket) // Linux int closesocket(int _socket) // Windows
# 端口复用
允许多个套接字同时监听同一个端口
int opt = 1; setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
# I/O多路复用模型,及其函数
什么是I/O多路复用?当一个程序有多个I/O任务时,很有可能有部分任务需要去等待其他的操作,这时候一个一个等待,这样的串行编程太费时间了,可以将所有的文件描述符交给内核,让内核帮助程序管理,如果一个任务已经准备就绪,就通知程序某个文件描述符可以执行I/O任务了
# select函数
# 简介
这是一个跨平台的函数可以在Linux和Windows中使用,解决了服务端与多个客户端连接以及通> 讯问题,select是一个线性表,会从左边开始向右端逐个检测
# fd_set
用来定义一个集合,集合中存放所有需要管理的socket句柄
typedef struct fd_set { u_int fd_count; SOCKET fd_array[FD_SETSIZE]; } fd_set;
# 集合操作
FD_ZEOR(fd_set*); //初始化,清空 FD_SET(int fd,fd_set*) //添加 FD_CLR(int fd,fd_set*) //删除 FD_ISSET(int fd,fd_set*) //查询
# 函数简介
传入一个用FD_SET提前设置好的fd_set集合,select会检查fd_set中的每个socket,如果某个socket已经准备好了,那select会将它在fd_set的集合位置为1,如果没有准备好的集合位置为0 例如,如果是读集合,那fd_set集合位为1,说明该socket已经有得读了
#include <sys/select.h> int select( __in int maxfd, __inout fd_set* readSet, __inout fd_set* writeSet, __inout fd_set* errorSet, __int const struct timeval* timeout );
# 时间结构体
struct timeval{ time_t tv_sec; //seconds suseconds_t tv_usec; //microseconds }
# 返回值
return value:
大于 0 The num of fd is readied 等于 0 time out 小于 0 error
# 大致实例
在该文件夹中select.cpp有完成实例
fd_set read_fd_set FD_ZERO(&read_fd_set); FD_SET(fd,&read_fd_set);// 假设fd为客户端句柄 timeval tv = {1,0} // 设置超时时间 int res = select(1024,&read_fd_set,NULL,NULL&tv); if(res == 0 || res == SOCKET_ERROR){ return 0; } if(FD_ISSET(fd,&read_fd_set)){ // 有得读了 }
# poll函数(只能在Linux系统中使用)
int poll(struct pollfd * fds, unsigned long nfds, int timeout) struct pollfd{ int fd;//套接字句柄 short events;//希望的事件 short revents;//实际的事件 } fds 传入pollfd数组 nfds 传入的数组大小 timeout INFTIM=无限等待,0=立刻返回,数值=超时时间
# epoll函数
此函数只能在Linux中使用 #include <sys/epoll.h>
# epoll_create
/*to create epoll fd*/ int epoll_create(int size); // size greater than 0 // return a epoll fd
# epoll_ctl
/*to contral fd from epoll*/ int epoll_ctl(int epollfd, int option, int fd, struct epoll_event* event); /* options: EPOLL_CTL_ADD // add fd to epoll EPOLL_CTL_MOD // modify fd from epoll EPOLL_CTL_DEL // delete fd from epoll */
# epoll_event
struct epoll_event { uint32_t events; epoll_data_t data; } /* events EPOLLIN // 可读 EPOLLOUT // 可写 */
# epoll_data
typedef struct epoll_data { void * ptr; int fd; // 一般只是用这个,用来保存这个事件是属于那个fd的 uint32_t u32; uint64_t u64; }epoll_data_t;
# epoll_wait
/*to wait epoll_event*/ int epoll_wait( int epollfd, // epoll文件描述符 struct epoll_event *eventBack, // 一个数组用来作为回调的数据 int max_eventBack, // 数组大小 int timeout ); // return the num of event /*timeout options: = 0 noblock > 0 wait n ms -1 block */