linux——TCP服务器获取客户端IP地址

之前的服务器端代码不灵活,今天对他进行优化

1、优化1:使用INADDR_ANY绑定IP

旧代码

复制代码
sin.sin_addr.s_addr = inet_addr("192.168.88.129");

优化后

复制代码
sin.sin_addr.s_addr = INADDR_ANY;

这个优化的意思

  • 旧写法 :服务器只绑定固定 IP 换一台电脑、换一个网卡、换一个网段 → 连接失败!

  • 新写法 INADDR_ANY服务器绑定本机所有网卡 IP! 不管服务器 IP 是多少不管是哪个网卡不管是内网、外网、虚拟机客户端都能连接!

优点总结

  1. 不挑 IP
  2. 不挑网卡
  3. 代码可移植性极强
  4. 正式项目服务器 100% 这么写

2、优化2:accept 时获取客户端 IP + 端口(正式服务器必备)

旧代码

复制代码
newfd = accept(fd, NULL, NULL);

只拿连接,不关心客户是谁

优化后

复制代码
// 新版
struct sockaddr_in cin;
socklen_t addrlen = sizeof(cin);
newfd = accept(fd,(struct sockaddr *)&cin,&addrlen);

char ipv4_addr[16];
inet_ntop(AF_INET, &cin.sin_addr, ipv4_addr, sizeof(ipv4_addr));

printf("Client:(%s,%d) is connect\n", ipv4_addr, ntohs(cin.sin_port));

复制代码
struct sockaddr_in cin;
  • cin = client in 的意思
  • 作用:准备一个空盒子,用来装客户端的 IP、端口
  • 这个结构体和服务端的 sin 一模一样,只是名字不同

复制代码
socklen_t addrlen = sizeof(cin);
  • addrlen:地址结构体的长度
  • 为什么要写?accept 函数要求必须传一个 "地址长度的指针"
  • 这是固定写法,背下来

复制代码
newfd = accept(fd, (struct sockaddr *)&cin, &addrlen);

旧版后面的两个参数是NULL,优化后会自动的把客户端的IP、端口存到cin里!

复制代码
char ipv4_addr[16];

用来存字符串格式的IP

复制代码
inet_ntop(AF_INET, &cin.sin_addr, ipv4_addr, sizeof(ipv4_addr));

把cin里的二进制IP转成字符串IP

复制代码
printf("Client:(%s,%d) is connect\n",
       ipv4_addr,
       ntohs(cin.sin_port));

打印两个东西:

  1. ipv4_addr → 客户端 IP
  2. ntohs(cin.sin_port) → 客户端端口

为什么用 ntohs?

因为端口在网络里是网络字节序,要转成主机字节序才能正常打印。

ntohs = network to host short

这个优化的意思

旧版:

只知道有人连接了,但不知道是谁连的

新版:

accept 时自动把客户端的 IP 地址、客户端端口号取出来,然后打印

这个优化的 3 个好处

  1. 可以知道谁连接了服务器

  2. 方便日志记录

  3. 正式网络程序必须这么写

    #include<stdio.h>
    #include <sys/types.h> /* See NOTES */
    #include <sys/socket.h>
    #include <unistd.h>
    #include<stdlib.h>
    #include <strings.h>
    #include <arpa/inet.h>
    #include<string.h>

    #define QUIT_STR "QUIT"
    #define BUFSIZE 1024
    #define BACKLOG 5
    #define SERV_IP 5001
    #define SERV_IP_ADDR "192.168.88.129"
    int main()
    {
    int fd = -1;

    复制代码
     struct sockaddr_in sin;
     //1.socket
     fd = socket(AF_INET,SOCK_STREAM,0);
     if(fd<0)
     {
     	perror("socket");
     	exit(1);
     }
    
     bzero(&sin,sizeof(sin));
    
     sin.sin_family = AF_INET;
     sin.sin_port = htons(SERV_IP);
     //sin.sin_addr.s_addr = inet_addr(SERV_IP_ADDR);  
     sin.sin_addr.s_addr = INADDR_ANY;
     /*if(inet_pion(AF_INET,SERV_IP_ADDR,(void *)sin.sin_addr.s_addr) != 1)
       {
       perror("inet_pton");
       exit(1);
       }
       */
     //2.bind
     if(bind(fd,(struct sockaddr *)&sin,sizeof(sin)) <0)
     {
     	perror("bind");
     	exit(0);
     }
     //3.listen
     if(listen(fd,BACKLOG) < 0)
     {
     	perror("listen");
     	exit(1);
     }
     
     //4.accept
     /*int newfd = -1;
     newfd = accept(fd,NULL,NULL);
     if(newfd < 0)
     {
     	perror("accept");
     	exit(1);
     }
     */
     int newfd = -1;
     struct sockaddr_in cin;
     socklen_t addrlen = sizeof(cin);
     newfd = accept(fd,(struct sockaddr *)&cin,&addrlen);
     if(newfd < 0)
     {
     	perror("accept");
     	exit(1);
     }
    
     char ipv4_addr[16];
     if(!inet_ntop(AF_INET,(void *)&cin.sin_addr,ipv4_addr,sizeof(cin)))
     {
     	perror("inet_ntop");
     	exit(1);
     }
     printf("Client:(%s,%d) is connect\n",ipv4_addr,ntohs(cin.sin_port));
    
     char buf[BUFSIZE];
     int ret = -1;
     //read
     while(1)
     {
     	do
     	{
     	bzero(buf,BUFSIZE);
     	ret = read(newfd,buf,BUFSIZE-1);
     	}while(ret < 1);
     	if(ret < 0)
     	{
     		exit(1);
     	}
     	if(!ret)
     	{
     		break;
     	}
     	printf("receive data:%s\n",buf);
    
     	if(!strncasecmp(buf,QUIT_STR,strlen(QUIT_STR)))
     	{
     		printf("Client is exiting!\n");
     		break;
     	}
     }
     
     close(newfd);
     close(fd);
    
     return 0;

    }

相关推荐
隐擎fox1 分钟前
跨越传输层防线:深入 TCP/IP 协议栈指纹(p0f)原理与 Python 原始套接字检测实战
python·网络协议·tcp/ip·网络安全·dns
网硕互联的小客服10 分钟前
服务器可以远程连接,但是为什么无法Ping通?如何解决处理?
运维·服务器
Dr_Fourier31 分钟前
mmap的使用与底层原理
linux·c++
Lydia 不加班35 分钟前
Windows 服务器 人大金仓 54321 端口放行完整步骤
运维·服务器·windows
Token掘金室1 小时前
JSON模式结构化输出报错
java·服务器·json
一技安身1 小时前
【信创】外网打包ragflow镜像并导入内网银河麒麟V10arm64服务器
运维·服务器
1314lay_10071 小时前
asp文件的服务器控件要使用CssClass,否则会失效。导致上传服务器之后,按钮禁用时的效果出问题了,没有正确应用样式
服务器
IT小白杨1 小时前
TikTok多账号运营体系安全运营攻略:移动端优先架构下的环境隔离技术解析
大数据·经验分享·tcp/ip·安全·架构·指纹浏览器
T01156182 小时前
全栈项目实战手记|艺培场馆课时预约小程序全项目开发历程完整复盘总结
运维·服务器·小程序
库玛西2 小时前
深度解构高并发利器:纯事件驱动 Reactor 模式的设计哲学与工程实践
服务器·开发语言·c++·笔记·tcp/ip