eduwin 网络模块 API
头文件:
eduwin_net.h(或通过eduwin.h统一引用)
基于 Winsock2 + WinHTTP,零外部依赖。提供 TCP、UDP、HTTP、DNS 四层能力。
初始化 / 清理
int net_init(void);
void net_cleanup(void);
const char* net_error(void);
void net_free(void *ptr);
所有网络操作前必须先调 net_init(),退出时调 net_cleanup()。net_error() 返回最近一次操作的错误描述(仅调试用,值不会 auto-clear)。net_free() 释放模块内部分配的内存(如 tcp_peer_addr 的返回值)。
net_init();
// ... 网络操作 ...
net_cleanup();
DNS 解析
int dns_lookup(const char *hostname, char *ip, int ip_size);
将域名解析为 IPv4 地址字符串。返回 0 成功,ip 中存储点分十进制 IP(如 "202.202.0.100")。
char ip[64];
if (dns_lookup("www.xtu.edu.cn", ip, sizeof(ip)) == 0)
printf("IP: %s", ip); // 输出: IP: 202.202.0.100
TCP
typedef struct tcp_s tcp_t;
// 客户端连接
tcp_t* tcp_connect(const char *host, int port);
// 服务端监听
tcp_t* tcp_listen(int port);
tcp_t* tcp_accept(tcp_t *server);
// 收发
int tcp_send(tcp_t *conn, const char *data, int len);
int tcp_recv(tcp_t *conn, char *buf, int buf_size);
int tcp_recv_timeout(tcp_t *conn, char *buf, int buf_size, int timeout_ms);
// 工具
char* tcp_peer_addr(tcp_t *conn); // 需 net_free
void tcp_close(tcp_t *conn);
tcp_recv_timeout 的 timeout_ms 传 -1 表示无限等待。tcp_peer_addr 返回格式 "ip:port"。
// 时间服务器查询示例
tcp_t *conn = tcp_connect("time.nist.gov", 13);
if (conn) {
char buf[1024] = {0};
int n = tcp_recv_timeout(conn, buf, sizeof(buf)-1, 5000);
if (n > 0) printf("时间: %s", buf);
tcp_close(conn);
}
UDP
typedef struct udp_s udp_t;
udp_t* udp_create(int port); // port=0 自动分配
int udp_send(udp_t *sock, const char *host, int port,
const char *data, int len);
int udp_recv(udp_t *sock, char *buf, int buf_size,
char *src_ip, int *src_port, int timeout_ms);
void udp_close(udp_t *sock);
udp_create(0) 创建绑定到随机端口的 UDP 套接字。udp_recv 的 src_ip 和 src_port 可传 NULL 跳过读取。
HTTP
typedef struct http_s http_t;
http_t* http_get(const char *url);
http_t* http_post(const char *url, const char *body,
const char *content_type,
const char *auth_header);
int http_status(http_t *resp);
const char* http_body(http_t *resp);
int http_body_len(http_t *resp);
void http_free(http_t *resp);
支持 HTTPS(通过 WinHTTP)。content_type 和 auth_header 可传 NULL 跳过。
// 获取公网 IP
http_t *resp = http_get("https://httpbin.org/ip");
if (resp) {
printf("HTTP %d: %s", http_status(resp), http_body(resp));
http_free(resp);
}
URL 编码
char* url_encode(const char *str); // 需 net_free
对字符串进行 URL 百分号编码。适用于构造自定义 HTTP 查询参数。
WebSocket Hub
基于原生 Winsock WebSocket 协议(RFC 6455)实现的轻量级 pub/sub 消息枢纽。单线程、无锁、非阻塞轮询。
设计思路
- 服务端监听端口,接受 WS 客户端连接
- 客户端通过 JSON 指令订阅/取消订阅话题
- 消息通过话题路由,发送者不会收到自己的消息
- 所有客户端对等,不分角色
创建 / 关闭
typedef struct ws_hub_s ws_hub_t;
ws_hub_t* ws_hub_create(int port);
void ws_hub_close(ws_hub_t *hub);
ws_hub_create 在指定端口启动 WS 服务器(ws://)。
连接管理
int ws_hub_accept(ws_hub_t *hub, int timeout_ms);
int ws_hub_count(ws_hub_t *hub);
int ws_hub_conn_id(ws_hub_t *hub, int index);
void ws_hub_disconnect(ws_hub_t *hub, int conn_id);
ws_hub_accept— 接受新连接,返回conn_id(-1=超时/错误)ws_hub_count— 当前连接数ws_hub_conn_id— 按索引获取conn_idws_hub_disconnect— 断开指定连接
订阅 / 发布
int ws_hub_subscribe(ws_hub_t *hub, int conn_id, const char *topic);
int ws_hub_unsubscribe(ws_hub_t *hub, int conn_id, const char *topic);
int ws_hub_publish(ws_hub_t *hub, int sender_id, const char *topic,
const char *data, int len);
int ws_hub_recv(ws_hub_t *hub, int conn_id,
char *buf, int buf_size, int timeout_ms);
int ws_hub_poll(ws_hub_t *hub, int timeout_ms);
ws_hub_subscribe— 订阅话题(一个连接可订阅多个)ws_hub_unsubscribe— 取消订阅ws_hub_publish— 向某话题所有订阅者(排除发送者)推送消息ws_hub_recv— 接收指定连接的一条消息ws_hub_poll— 轮询所有连接,返回有消息待读的conn_id(-1=无)
限制
| 项 | 上限 |
|---|---|
| 最大连接数 | 64 |
| 话题名长度 | 64 字符 |
| 每连接可订阅话题数 | 16 |
| 单条消息最大长度 | 16 KB |
示例
ws_hub_t *hub = ws_hub_create(9099);
if (!hub) { /* 错误处理 */ }
while (g_running) {
/* 接受新连接 */
int cid = ws_hub_accept(hub, 200);
if (cid >= 0) {
ws_hub_subscribe(hub, cid, "agent");
ws_hub_subscribe(hub, cid, "js");
}
/* 轮询消息 */
int ready = ws_hub_poll(hub, 200);
if (ready < 0) continue;
char buf[16384];
int len = ws_hub_recv(hub, ready, buf, sizeof(buf) - 1, 0);
if (len <= 0) { ws_hub_disconnect(hub, ready); continue; }
buf[len] = '\0';
/* 解析 JSON,按 topic 发布 */
// ws_hub_publish(hub, ready, topic, buf, len);
}
ws_hub_close(hub);
完整示例
参见 samples/network_info_demo/、samples/ai_browser_demo/。
编译要求
链接时需要额外两个库:
ws2_32.lib winhttp.lib
对应的 build.bat 模板:
cl main.c /Fe:demo.exe /link eduwin.lib user32.lib gdi32.lib gdiplus.lib comctl32.lib comdlg32.lib shell32.lib winmm.lib ws2_32.lib winhttp.lib