socket
Linux:select、poll、epoll,Windows:IOCP,BSD/Mac:Kqueue,在这之上封装了 Libevent 等库。
客户端
#include <arpa/inet.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> #include <unistd.h> int main() { int fd = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); struct sockaddr_in server_addr = {.sin_family = AF_INET, .sin_port = htons(6666), .sin_addr.s_addr = inet_addr("127.0.0.1")}; connect(fd, (struct sockaddr *) &server_addr, sizeof(server_addr)); uint8_t type = 9; send(fd, &type, sizeof(uint8_t), 0); char *value = "hello!"; size_t length = sizeof(char) * (strlen(value) + 1); send(fd, &length, sizeof(size_t), 0); send(fd, value, length, 0); recv(fd, &type, sizeof(uint8_t), MSG_WAITALL); recv(fd, &length, sizeof(size_t), MSG_WAITALL); recv(fd, value, sizeof(unsigned char) * length, MSG_WAITALL); printf("Received TLV data - Type: %u, Length: %lu, Value: %s\n", type, length, value); close(fd); return EXIT_SUCCESS; }
服务端
#include <arpa/inet.h> #include <netinet/in.h> #include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> #include <unistd.h> int main() { int server_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); struct sockaddr_in server_addr = {.sin_family = AF_INET, .sin_port = htons(6666), .sin_addr.s_addr = htonl(INADDR_ANY)}; bind(server_fd, (struct sockaddr *) &server_addr, sizeof(server_addr)); listen(server_fd, SOMAXCONN); while (true) { struct sockaddr_in client_addr; socklen_t client_addr_len = sizeof(struct sockaddr_in); int client_fd = accept(server_fd, (struct sockaddr *) &client_addr, &client_addr_len); printf("client connected: %s:%d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port)); uint8_t type; recv(client_fd, &type, sizeof(uint8_t), MSG_WAITALL); size_t length; recv(client_fd, &length, sizeof(size_t), MSG_WAITALL); unsigned char value[length]; recv(client_fd, value, sizeof(unsigned char) * length, MSG_WAITALL); printf("Received TLV data - Type: %u, Length: %lu, Value: %s\n", type, length, value); send(client_fd, &type, sizeof(uint8_t), 0); send(client_fd, &length, sizeof(size_t), 0); send(client_fd, value, sizeof(unsigned char) * length, 0); close(client_fd); } close(server_fd); return EXIT_SUCCESS; }
服务端,多线程
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <arpa/inet.h> #include <netinet/in.h> #include <unistd.h> #include <pthread.h> #include <stdbool.h> #include <string.h> #include <stdio.h> #include <stdlib.h> #include <sys/socket.h> void *handle_client(void *arg) { int client_fd = *((int *) arg); struct sockaddr_in client_addr; socklen_t client_addr_len = sizeof(struct sockaddr_in); getpeername(client_fd, (struct sockaddr *) &client_addr, &client_addr_len); printf("Client connected: %s:%d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port)); uint8_t type; recv(client_fd, &type, sizeof(uint8_t), MSG_WAITALL); size_t length; recv(client_fd, &length, sizeof(size_t), MSG_WAITALL); unsigned char value[length]; recv(client_fd, value, sizeof(unsigned char) * length, MSG_WAITALL); printf("Received TLV data - Type: %u, Length: %lu, Value: %s\n", type, length, value); send(client_fd, &type, sizeof(uint8_t), 0); send(client_fd, &length, sizeof(size_t), 0); send(client_fd, value, sizeof(unsigned char) * length, 0); close(client_fd); pthread_exit(NULL); } int main(int argc, char *argv[]) { int server_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); struct sockaddr_in server_addr = {.sin_family = AF_INET, .sin_port = htons(6666), .sin_addr.s_addr = htonl(INADDR_ANY)}; bind(server_fd, (struct sockaddr *) &server_addr, sizeof(server_addr)); listen(server_fd, SOMAXCONN); while (true) { struct sockaddr_in client_addr; socklen_t client_addr_len = sizeof(struct sockaddr_in); int client_fd = accept(server_fd, (struct sockaddr *) &client_addr, &client_addr_len); pthread_t tid; pthread_create(&tid, NULL, handle_client, &client_fd); pthread_detach(tid); } close(server_fd); return EXIT_SUCCESS; }
服务端,select
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <arpa/inet.h> #include <netinet/in.h> #include <unistd.h> #include <stdbool.h> #include <string.h> #include <stdio.h> #include <stdlib.h> #include <sys/socket.h> int main(int argc, char *argv[]) { int server_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); struct sockaddr_in server_addr = {.sin_family = AF_INET, .sin_port = htons(6666), .sin_addr.s_addr = htonl(INADDR_ANY)}; bind(server_fd, (struct sockaddr *) &server_addr, sizeof(server_addr)); listen(server_fd, SOMAXCONN); fd_set readfds; FD_ZERO(&readfds); FD_SET(server_fd, &readfds); int max_fd = server_fd; while (true) { select(max_fd + 1, &readfds, NULL, NULL, NULL); for (int fd = 0; fd <= max_fd; fd++) { if (!FD_ISSET(fd, &readfds)) continue; if (fd == server_fd) { struct sockaddr_in client_addr; socklen_t client_addr_len = sizeof(struct sockaddr_in); int client_fd = accept(server_fd, (struct sockaddr *) &client_addr, &client_addr_len); printf("Client connected: %s:%d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port)); FD_SET(client_fd, &readfds); if (client_fd > max_fd) max_fd = client_fd; } else { uint8_t type; recv(fd, &type, sizeof(uint8_t), MSG_WAITALL); size_t length; recv(fd, &length, sizeof(size_t), MSG_WAITALL); unsigned char value[length]; recv(fd, value, sizeof(unsigned char) * length, MSG_WAITALL); printf("Received TLV data - Type: %u, Length: %lu, Value: %s\n", type, length, value); send(fd, &type, sizeof(uint8_t), 0); send(fd, &length, sizeof(size_t), 0); send(fd, value, sizeof(unsigned char) * length, 0); close(fd); FD_CLR(fd, &readfds); } } } close(server_fd); return EXIT_SUCCESS; }
服务端,poll
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <arpa/inet.h> #include <netinet/in.h> #include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/poll.h> #include <sys/socket.h> #include <unistd.h> int main() { int server_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); struct sockaddr_in server_addr = {.sin_family = AF_INET, .sin_port = htons(6666), .sin_addr.s_addr = htonl(INADDR_ANY)}; bind(server_fd, (struct sockaddr *) &server_addr, sizeof(server_addr)); listen(server_fd, SOMAXCONN); struct pollfd fds[SOMAXCONN]; for (int i = 0; i < SOMAXCONN; i++) fds[i].fd = -1; fds[0].fd = server_fd, fds[0].events = POLLIN; while (true) { poll(fds, SOMAXCONN, -1); if (fds[0].revents & POLLIN) { struct sockaddr_in client_addr; socklen_t client_addr_len = sizeof(struct sockaddr_in); int client_fd = accept(server_fd, (struct sockaddr *) &client_addr, &client_addr_len); printf("client connected: %s:%d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port)); for (int i = 0; i < SOMAXCONN; i++) { if (fds[i].fd == -1) { fds[i].fd = client_fd, fds[i].events = POLLIN; break; } } } for (int i = 1; i < SOMAXCONN; i++) { if (!(fds[i].revents & POLLIN)) continue; int client_fd = fds[i].fd; uint8_t type; recv(client_fd, &type, sizeof(uint8_t), MSG_WAITALL); size_t length; recv(client_fd, &length, sizeof(size_t), MSG_WAITALL); unsigned char value[length]; recv(client_fd, value, sizeof(unsigned char) * length, MSG_WAITALL); printf("Received TLV data - Type: %u, Length: %lu, Value: %s\n", type, length, value); send(client_fd, &type, sizeof(uint8_t), 0); send(client_fd, &length, sizeof(size_t), 0); send(client_fd, value, sizeof(unsigned char) * length, 0); close(client_fd); fds[i].fd = -1; } } close(server_fd); return EXIT_SUCCESS; }
服务端,epoll
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <arpa/inet.h> #include <fcntl.h> #include <netinet/in.h> #include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/epoll.h> #include <sys/socket.h> #include <unistd.h> int main() { int server_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); // int optval = 1; // setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); // setsockopt(server_fd, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval)); struct sockaddr_in server_addr = {.sin_family = AF_INET, .sin_port = htons(6666), .sin_addr.s_addr = htonl(INADDR_ANY)}; bind(server_fd, (struct sockaddr *) &server_addr, sizeof(server_addr)); listen(server_fd, SOMAXCONN); int epoll_fd = epoll_create1(0); struct epoll_event events[SOMAXCONN], event = {.data.fd = server_fd, .events = EPOLLIN}; epoll_ctl(epoll_fd, EPOLL_CTL_ADD, server_fd, &event); while (true) { int nfds = epoll_wait(epoll_fd, events, SOMAXCONN, -1); for (int i = 0; i < nfds; i++) { if (events[i].data.fd == server_fd) { struct sockaddr_in client_addr; socklen_t client_addr_len = sizeof(struct sockaddr_in); int client_fd = accept(server_fd, (struct sockaddr *) &client_addr, &client_addr_len); printf("client connected: %s:%d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port)); // fcntl(client_fd, F_SETFL, fcntl(client_fd, F_GETFL, 0) | O_NONBLOCK); // 设置客户端 socket 为非阻塞模式 event.data.fd = client_fd, event.events = EPOLLIN | EPOLLET; // 设置为边缘触发模式 epoll_ctl(epoll_fd, EPOLL_CTL_ADD, client_fd, &event); } else { int client_fd = events[i].data.fd; uint8_t type; recv(client_fd, &type, sizeof(uint8_t), MSG_WAITALL); size_t length; recv(client_fd, &length, sizeof(size_t), MSG_WAITALL); unsigned char value[length]; recv(client_fd, value, sizeof(unsigned char) * length, MSG_WAITALL); printf("Received TLV data - Type: %u, Length: %lu, Value: %s\n", type, length, value); send(client_fd, &type, sizeof(uint8_t), 0); send(client_fd, &length, sizeof(size_t), 0); send(client_fd, value, sizeof(unsigned char) * length, 0); epoll_ctl(epoll_fd, EPOLL_CTL_DEL, client_fd, NULL); close(client_fd); } } } close(epoll_fd); close(server_fd); return EXIT_SUCCESS; }