下面分别以TCP、UDP为例介绍两者的流程图和代码实现:
- TCP
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <arpa/inet.h> #define SERVER_PORT 8888 #define SERVER_IP "192.168.1.100" int main() { // 1. 创建监听套接字 int fd = socket(AF_INET, SOCK_STREAM, 0); if (fd == -1) { perror("fail fo socket!"); return -1; } printf("create socket fd[%d] success!\n"); // 2. 绑定监听套接字到本地IP和port struct sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htons(SERVER_PORT); inet_pton(AF_INET, SERVER_IP, &addr.sin_addr); int ret = bind(fd, (struct sockaddr*)&addr, sizeof(addr)); if (ret == -1) { perror("fail to bind!"); return -2; } printf("bind success!\n"); // 3. 设置监听 ret = listen(fd, 128); if (ret == -1) { perror("fail to listen!"); return -3; } printf("listen success!\n"); // 4. 阻塞等待,等待连接到达,连接成功后返回通信用的套接字 struct sockaddr_in c_addr; int c_addr_len = sizeof(c_addr); int c_fd = accept(fd, (struct sockaddr*)&c_addr, &c_addr_len); if (c_fd == -1) { perror("fail to accept!"); return -4; } printf("accept success!\n"); // 5. 开始通信 char buff[1024]; char ip[32]; memset(buff, 0, sizeof(buff)); memset(ip, 0, sizeof(ip)); int len = read(c_fd, buff, sizeof(buff)); if (len > 0) { printf("client %s:%d >> %s\n", inet_ntop(AF_INET, &c_addr.sin_addr, ip , sizeof(ip)), ntohs(c_addr.sin_port), buff); write(c_fd, buff, len); } else if (len == 0) { printf("connect close!"); } else { printf("connect fail!"); } // 6. 关闭套接字 close(fd); close(c_fd); return 0; }client端:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <arpa/inet.h> #define SERVER_PORT 8888 #define SERVER_IP "192.168.1.100" int main() { // 1. 创建通信套接字 int fd = socket(AF_INET, SOCK_STREAM, 0); if (fd == -1) { perror("fail fo socket!"); return -1; } printf("create socket success!\n"); // 2. 连接服务器 struct sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htons(SERVER_PORT); inet_pton(AF_INET, SERVER_IP, &addr.sin_addr); int ret = connect(fd, (struct sockaddr*)&addr, sizeof(addr)); if (ret == -1) { perror("fail to connect!"); return -2; } printf("connect success!\n"); // 3. 通信 char buff[1024]; char ip[32]; sprintf(buff, "Hello, this is a test connection with the server!"); int len = send(fd, buff, strlen(buff) + 1, 0); memset(buff, 0, sizeof(buff)); memset(ip, 0, sizeof(ip)); len = recv(fd, buff, sizeof(buff), 0); if (len > 0) { printf("server %s:%d >> %s\n", inet_ntop(AF_INET, &addr.sin_addr, ip , sizeof(ip)), ntohs(addr.sin_port), buff); } else if (len == 0) { printf("connect close!\n"); } else { perror("recv fail!\n"); } // 4. 关闭套接字 close(fd); return 0; }上述代码就是实现一个简单的socket通信过程,服务器和客户端收发一次消息后便关闭通信。 就是上面一个简单的通信过程,发现实现起来也并非一帆风顺,途中数次碰到问题,下面记录下踩到的一些坑: 1.fail to connect!: No route to host server端代码和client端代码分别在两台虚拟机上运行时,client端一运行就报fail to connect!: No route to host错误,检查发现双发是能否ping通,搜索发现可能是防火墙打开导致这个问题,使用以下命令查看防火墙是开着的:
[root@localhost socket]# systemctl status firewalld.service ● firewalld.service - firewalld - dynamic firewall daemon Loaded: loaded (/usr/lib/systemd/system/firewalld.service; enabled; vendor preset: enabled) Active: active (running) since Fri 2022-12-30 21:44:51 EST; 42min ago Docs: man:firewalld(1) Main PID: 693 (firewalld) CGroup: /system.slice/firewalld.service └─693 /usr/bin/python2 -Es /usr/sbin/firewalld --nofork --nopid Dec 30 21:44:50 localhost.localdomain systemd[1]: Starting firewalld - dynamic firewall daemon... Dec 30 21:44:51 localhost.localdomain systemd[1]: Started firewalld - dynamic firewall daemon. Dec 30 21:44:51 localhost.localdomain firewalld[693]: WARNING: AllowZoneDrifting is enabled. This is considered an insecure configur...t now. Hint: Some lines were ellipsized, use -l to show in full.试着关闭防火墙后运行了下程序,发现能成功通信,果然是防火墙的原因。 2.server端显示client的ip和port错误 在运行上述代码时,发现在server端打印连接的client的ip和port一直都有问题并非实际的ip和port。排查了半天才发现传给accpet的第三个参数是表示sockaddr结构体的大小,并非随便传一个值都行。
struct sockaddr_in c_addr; int c_addr_len = sizeof(c_addr); int c_fd = accept(fd, (struct sockaddr*)&c_addr, &c_addr_len);
标签:addr,ip,编程,网络,len,fd,sizeof,buff,socket From: https://www.cnblogs.com/chien/p/17328746.html