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;

    }

相关推荐
嵌入式×边缘AI:打怪升级日志1 小时前
100ASK-T113 Pro 开发板 Bootloader 完全开发指南
linux·ubuntu·bootloader
lzhdim1 小时前
SQL 入门 12:SQL 视图:创建、修改与可更新视图
java·大数据·服务器·数据库·sql
2401_873479402 小时前
断网时如何实时判断IP归属?嵌入本地离线库,保障风控不中断
运维·服务器·网络
charlie1145141912 小时前
Linux 字符设备驱动:cdev、设备号与设备模型
linux·开发语言·驱动开发·c
handler012 小时前
Linux 内核剖析:进程优先级、上下文切换与 O(1) 调度算法
linux·运维·c语言·开发语言·c++·笔记·算法
zhouwy1132 小时前
Linux进程与线程编程详解
linux·c++
7ACE3 小时前
Wireshark TS | TLP 超时时间
网络·网络协议·tcp/ip·wireshark·tcpdump
我星期八休息3 小时前
IT疑难杂症诊疗室:AI时代工程师Superpowers进化论
linux·开发语言·数据结构·人工智能·python·散列表
切糕师学AI3 小时前
深入解析 Zsh 与 Oh-My-Zsh:打造高效现代化终端
linux·终端·zsh
切糕师学AI4 小时前
Ubuntu 下 Git 完全使用指南
linux·git·ubuntu