#Header
#include "co/sock.h"
The API is in the co namespace. Before use, you need to call flag::parse(argc, argv); at the beginning of main.
sock_t is in the global namespace.
#Overview
- Coroutine-based socket API.
- I/O-related APIs do not block the scheduling thread and must be called inside a coroutine.
- On error, use
co::error()/co::strerror()to get error information.
#Address co::sockaddr
struct sockaddr {
sockaddr();
sockaddr(const char* host, uint16 port);
bool valid() const;
int af() const;
};
- Supports IPv4, IPv6, and domain name resolution.
af()returnsAF_INETorAF_INET6.- Can be printed directly, in the format
127.0.0.1:8080.
#I/O Event Types
enum ev_t {
ev_read = 1,
ev_write = 2,
};
- Bitwise OR combination is not supported.
#Creating a Socket
sock_t co::tcp_socket(int af=0);
sock_t co::udp_socket(int af=0);
sock_t co::tcp_server_socket(const char* host, uint16 port, int backlog=4096);
af=0defaults toAF_INET.- The created socket is already non-blocking.
tcp_server_socket: creates a TCP socket, binds the address, and listens.
#Socket Operations
int co::close(sock_t fd, int ms=0);
int co::bind(sock_t fd, const sockaddr& addr);
int co::listen(sock_t fd, int backlog=4096);
int co::connect(sock_t fd, const sockaddr& addr, int ms=-1);
sock_t co::accept(sock_t fd, sockaddr* addr=nullptr);
close(fd, ms): delays closing bymsmilliseconds to prevent malicious attacks.connect:ms=-1means no timeout; the timeout error code isETIMEDOUT.acceptreturns the socket on success and(sock_t)-1on error; the others return 0 on success and -1 on error.
#Send and Receive
int co::recv(sock_t fd, void* buf, int n, int ms=-1);
int co::recvn(sock_t fd, void* buf, int n, int ms=-1);
int co::recvfrom(sock_t fd, void* buf, int n, sockaddr& addr, int ms=-1);
int co::send(sock_t fd, const void* buf, int n, int ms=-1);
int co::sendto(sock_t fd, const void* buf, int n, const sockaddr& addr, int ms=-1);
recv: single read, may return fewer thannbytes.recvn: reads exactlynbytes, suitable for protocols with a fixed-length header.recvfrom: UDP receive; when the function returns,addris filled with the sender’s address.send: returningnon success means all data was sent; the state after an error or timeout is undefined.sendto: UDP send.ms=-1means no timeout; the timeout error code isETIMEDOUT.
#Socket Options
void co::set_reuseaddr(sock_t fd);
void co::set_tcp_nodelay(sock_t fd);
void co::set_tcp_keepalive(sock_t fd);
void co::set_send_buffer_size(sock_t fd, int n);
void co::set_recv_buffer_size(sock_t fd, int n);
void co::set_nonblock(sock_t fd);
void co::set_cloexec(sock_t fd); // non-Windows
set_send_buffer_size/set_recv_buffer_sizemust be called before connecting.
#Others
int co::reset_tcp_socket(sock_t fd, int ms=0);
co::sockaddr co::peeraddr(sock_t fd);
reset_tcp_socket: resets the connection without enteringtimed_wait; generally used on the server side.peeraddr: returns the peer address.
#Examples
#TCP Client
#include "co/co.h"
#include "co/sock.h"
#include "co/print.h"
int main(int argc, char** argv) {
flag::parse(argc, argv);
go([] {
co::sockaddr addr("127.0.0.1", 8080);
sock_t fd = co::tcp_socket(addr.af());
int r = co::connect(fd, addr, 3000);
if (r != 0) {
co::println("connect failed: ", co::strerror());
co::close(fd);
return;
}
const char* msg = "hello";
r = co::send(fd, msg, 5, 3000);
co::println("sent ", r, " bytes");
char buf[128];
r = co::recv(fd, buf, sizeof(buf), 3000);
if (r > 0) co::println("recv: ", co::string(buf, r));
co::close(fd);
});
co::sleep(5000);
return 0;
}
#TCP Server
#include "co/co.h"
#include "co/sock.h"
#include "co/print.h"
int main(int argc, char** argv) {
flag::parse(argc, argv);
go([] {
sock_t s = co::tcp_server_socket("0.0.0.0", 8080);
if (s == (sock_t)-1) {
co::println("listen failed: ", co::strerror());
return;
}
while (true) {
co::sockaddr addr;
sock_t fd = co::accept(s, &addr);
if (fd == (sock_t)-1) break;
go([fd, addr] {
co::println("accepted: ", addr);
char buf[1024];
int n = co::recvn(fd, buf, 4);
if (n == 4) {
uint32 body_len = *(uint32*)buf;
co::string body;
body.resize(body_len);
co::recvn(fd, body.data(), body_len);
co::println("body: ", body);
}
co::close(fd);
});
}
co::close(s);
});
co::sleep(60000);
return 0;
}
#UDP
#include "co/co.h"
#include "co/sock.h"
#include "co/print.h"
int main(int argc, char** argv) {
flag::parse(argc, argv);
go([] {
sock_t fd = co::udp_socket();
co::sockaddr addr("127.0.0.1", 8080);
const char* msg = "ping";
co::sendto(fd, msg, 4, addr, 3000);
char buf[128];
co::sockaddr peer;
int n = co::recvfrom(fd, buf, sizeof(buf), peer, 3000);
if (n > 0) co::print("recvfrom ", peer, ": ", co::string(buf, n), '\n');
co::close(fd);
});
co::sleep(5000);
return 0;
}