socket编程代码示例

1. TCP server client模拟聊天对话框

server.c

cpp 复制代码
/* server.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define BUFFER_SIZE (1024)
#define IP_SIZE (100)
#define SERVER_SUCCESS (0)
#define SERVER_FAILURE (-1)
#define MAX_PENDDING_QUEUE (10)

typedef enum {
    false = 0,
    true = 1,
} bool;

static void server_usage(void)
{
    printf("#####################################\n");
    printf("#Server Usage:                      #\n");
    printf("#gcc server.c -o server             #\n");
    printf("#chmod 777 server                   #\n");
    printf("#./server <ip> <port>               #\n");
    printf("#                                   #\n");
    printf("#<ip>:server ip:192.168.xx.xx       #\n");
    printf("#<port>:server port:1024~65535      #\n");
    printf("#####################################\n");
    return;
}

int main(int argc, char *argv[])
{
    int listenfd = -1;
    int connectfd = -1;
    int ret;
    int recv_bytes;

    struct sockaddr_in serveraddr;
    struct sockaddr_in clientaddr;

    socklen_t peerlen;

    char server_buf[BUFFER_SIZE] = {0};
    char client_addr[IP_SIZE] = {0};

    if (argc < 3) {
        server_usage();
        return SERVER_FAILURE;
    }

    /* socket */
    listenfd = socket(AF_INET, SOCK_STREAM, 0);
    if (listenfd == -1) {
        printf("[ERROR]server socket failed, why:%s\n", strerror(errno));
        return SERVER_FAILURE;
    }
    printf("[DEBUG]server socket success, listenfd = %d\n", listenfd);

    /* serveraddr */
    memset(&serveraddr, 0x00, sizeof(serveraddr));
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_port = htons(atoi(argv[2]));
    inet_pton(AF_INET, argv[1], &serveraddr.sin_addr);

    /* bind */
    ret = bind(listenfd, (const struct sockaddr *)&serveraddr, sizeof(serveraddr));
    if (ret != 0) {
        printf("[ERROR]server bind failed, why:%s\n", strerror(errno));
        close(listenfd);
        return SERVER_FAILURE;
    }
    printf("[DEBUG]server bind success\n");

    /* listen */
    ret = listen(listenfd, MAX_PENDDING_QUEUE);
    if (ret != 0) {
        printf("[ERROR]server listen failed, why:%s\n", strerror(errno));
        close(listenfd);
        return SERVER_FAILURE;
    }
    printf("[DEBUG]server listen success\n");

    printf("server waiting for connect......\n\n");

    /* accept */
    while (true) {
        memset(&clientaddr, 0x00, sizeof(clientaddr));
        peerlen = sizeof(clientaddr);

        connectfd = accept(listenfd, (struct sockaddr *)&clientaddr, &peerlen);
        if (connectfd == -1) {
            printf("[ERROR]server accept failed, why:%s\n", strerror(errno));
            close(listenfd);
            return SERVER_FAILURE;
        }
        memset(client_addr, 0x00, sizeof(client_addr));
        inet_ntop(AF_INET, &clientaddr.sin_addr, client_addr, sizeof(client_addr));
        printf("[DEBUG]server connected, client ip:%s, port:%d\n\n", client_addr, ntohs(clientaddr.sin_port));

        /* send and recv */
        while (true) {

            memset(server_buf, 0x00, sizeof(server_buf));

            printf("\033[1m<--- \033[0m"), fflush(stdout);
            recv_bytes = recv(connectfd, server_buf, sizeof(server_buf), 0);
            if (recv_bytes == -1) {
                printf("[ERROR]server recv failed, why:%s\n", strerror(errno));
                close(connectfd);
                close(listenfd);
                return SERVER_FAILURE;
            } else if (recv_bytes == 0) {
                printf("[DEBUG]server detected client gone!\n");
                close(connectfd);
                break;
            }

            printf("client@%s:%d said:%s\n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port), server_buf);
            
            memset(server_buf, 0x00, sizeof(server_buf));
            printf("\033[1m---> \033[0m"), fflush(stdout);
            fgets(server_buf, sizeof(server_buf), stdin);
            send(connectfd, server_buf, sizeof(server_buf), 0);
            printf("\n");
        }
    }
    close(listenfd);
    return SERVER_SUCCESS;
}

client.c

cpp 复制代码
/* client.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define BUFFER_SIZE (1024)
#define CLIENT_SUCCESS (0)
#define CLIENT_FAILURE (-1)
#define MAX_PENDDING_QUEUE (10)

typedef enum {
    false = 0,
    true = 1,
} bool;

static void client_usage(void)
{
    printf("#####################################\n");
    printf("#Client Usage:                      #\n");
    printf("#gcc client.c -o client             #\n");
    printf("#chmod 777 client                   #\n");
    printf("#./client <ip> <port>               #\n");
    printf("#                                   #\n");
    printf("#<ip>:server ip:192.168.xx.xx       #\n");
    printf("#<port>:server port:1024~65535      #\n");
    printf("#####################################\n");
    return;
}


int main(int argc, char *argv[])
{
    int sockfd = -1;
    int ret;
    int recv_bytes;
    struct sockaddr_in serveraddr;
    char client_buf[BUFFER_SIZE] = {0};

    if (argc < 3) {
        client_usage();
        return CLIENT_FAILURE;
    }

    /* socket */
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd == -1) {
        printf("[ERROR]client socket failed, why:%s\n", strerror(errno));
        return CLIENT_FAILURE;
    }
    printf("[DEBUG]client socket success, sockfd = %d\n", sockfd);

    /* serveraddr */
    memset(&serveraddr, 0x00, sizeof(serveraddr));
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_port = htons(atoi(argv[2]));
    inet_pton(AF_INET, argv[1], &serveraddr.sin_addr);

    ret = connect(sockfd, (const struct sockaddr *)&serveraddr, sizeof(serveraddr));
    if (ret == -1) {
        printf("[ERROR]client connect failed, why:%s\n", strerror(errno));
        close(sockfd);
        return CLIENT_FAILURE;
    }
    printf("[DEBUG]client connect success\n");

    while (true) {

        memset(client_buf, 0x00, sizeof(client_buf));
        printf("\033[1m---> \033[0m"), fflush(stdout);
        fgets(client_buf, sizeof(client_buf), stdin);
        printf("\n");

        /* client said quit */
        if (strncmp(client_buf, "quit!", strlen("quit!")) == 0) {
            printf("[DEBUG]client said %s\n", client_buf);
            break;
        }

        send(sockfd, client_buf, sizeof(client_buf), 0);

        memset(client_buf, 0x00, sizeof(client_buf));

        printf("\033[1m<--- \033[0m"), fflush(stdout);
        recv_bytes = recv(sockfd, client_buf, sizeof(client_buf), 0);
        if (recv_bytes == -1) {
            printf("[ERROR]client recv failed, why:%s\n", strerror(errno));
            close(sockfd);
            return CLIENT_FAILURE;
        } else if(recv_bytes == 0) {
            printf("[DEBUG]client detected server gone!\n");
            break;
        }
        printf("server@%s:%d said:%s\n", argv[1], atoi(argv[2]), client_buf);
    }
    close(sockfd);
    printf("[DEBUG]<=====client exit\n");
    return CLIENT_SUCCESS;
}

wireshark抓包结果:

2. 用原始套接字模拟ping操作并解析IP包与ICMP包

cpp 复制代码
//This is a ping which can both send and receive ICMP packets
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <linux/tcp.h>
#include <netinet/ip_icmp.h>
#include <strings.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>

#define PING_SUCCESS (0)
#define PING_FAILURE (-1)
#define BUFFER_SIZE (1024)
#define MAGIC_NUM (3623)
//#define DEBUG

static unsigned short calc_cksum(unsigned short *addr, int len)
{
    int sum=0;
    unsigned short res=0;
    while( len > 1) {
        sum += *addr++;
        len -= 2;
    }

    if( len == 1) {
        *((unsigned char *)(&res))=*((unsigned char *)addr);
        sum += res;
    }

    sum = (sum >>16) + (sum & 0xffff);
    sum += (sum >>16) ;
    res = ~sum;
    return res;
}

int main(int argc, char *argv[])
{
    if (argc < 4) {
        printf("param error, usage: ./ping serverip -c <count>\n");
        return PING_FAILURE;
    }

    int count = atoi(argv[3]);
    char send_buff[BUFFER_SIZE] = {0};
    char recv_buff[BUFFER_SIZE] = {0};
    char src_buff[BUFFER_SIZE] = {0};

    int sockfd = -1;
    int recvfd = -1;
    int ret, i, lenfrom;

    struct sockaddr_in target_addr;
    struct sockaddr_in source_addr;

    /* socket */
    sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
    if (sockfd == -1) {
        printf("sockfd create for IPPROTO_ICMP failed, why:%s\n", strerror(errno));
        return PING_FAILURE;
    }
    recvfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
    if (recvfd == -1) {
        printf("recvfd create for IPPROTO_ICMP failed, why:%s\n", strerror(errno));
        close(sockfd);
        return PING_FAILURE;
    }

#ifdef DEBUG
    printf("[DEBUG]socket create for IPPROTO_ICMP success\n");
#endif

    memset(&target_addr, 0x00, sizeof(target_addr));
    ret = inet_pton(AF_INET, argv[1], &target_addr.sin_addr);
    if (ret != 1) {
        printf("bad ip address to be converted:%s\n", argv[1]);
        close(recvfd);
        close(sockfd);
        return PING_FAILURE;
    }

    struct icmp *picmp = (struct icmp *)send_buff;
    struct ip *pip = (struct ip*)recv_buff;
    struct icmp *p_recvicmp = (struct icmp *)(pip + 1);

    for (i = 0; i < count; i++) {
        memset(send_buff, 0x00, sizeof(send_buff));

        /*----TYPE----CODE----CHECKSUM----
         *----IDENTIFIER------SEQUENCE----
         *----OPTION----------------------
         */
        picmp->icmp_type = ICMP_ECHO; /* ECHO-REQUEST */
        picmp->icmp_code = 0;
        picmp->icmp_id = MAGIC_NUM;
        picmp->icmp_seq = i;
        picmp->icmp_cksum = calc_cksum((unsigned short *)picmp, 8);

        /* PING REQUEST */
        ret = sendto(sockfd, send_buff, 64, 0, (const struct sockaddr *)&target_addr, sizeof(target_addr)); /* ICMP total 64 bytes */
        if (ret == -1) {
            printf("turn %d sendto error, why:%s\n", i, strerror(errno));
            close(recvfd);
            close(sockfd);
            return PING_FAILURE;
        }

#ifdef DEBUG
        printf("[DEBUG]turn %d, %d bytes send...\n", i, ret);
#endif

        /* PING REPLY */
        memset(recv_buff, 0x00, sizeof(recv_buff));
        memset(&source_addr, 0x00, sizeof(source_addr));
        lenfrom = sizeof(source_addr);
        ret = recvfrom(sockfd, recv_buff, sizeof(recv_buff), 0, (struct sockaddr *)&source_addr, &lenfrom);
        if (ret == -1) {
            printf("turn %d recvfrom error, why:%s\n", i, strerror(errno));
            close(recvfd);
            close(sockfd);
            return PING_FAILURE;
        } else if (ret == 0) {
            printf("turn %d detect socket peer shutdown!\n", i);
            close(recvfd);
            close(sockfd);
            return PING_FAILURE;
        }

#ifdef DEBUG
        printf("[DEBUG]turn %d, %d bytes recv\n", i, ret);
        printf("[DEBUG]recv ip header len = %d\n", pip->ip_hl);
#endif

        if ((ret - (pip->ip_hl * 4)) < 8) { /* we assume ICMP at least 8 byte */
            printf("turn %d no ICMP reply!\n", i);
            close(recvfd);
            close(sockfd);
            return PING_FAILURE;
        }

        if ((p_recvicmp->icmp_type == ICMP_ECHOREPLY) && (p_recvicmp->icmp_id == MAGIC_NUM)) {
            /* get the src and dst addr */
            memset(src_buff, 0x00, sizeof(src_buff));

            /* from where? */
            inet_ntop(AF_INET, &source_addr.sin_addr, src_buff, sizeof(src_buff));

            printf("[myping]%d bytes from %s to %s: icmp_seq=%u ttl=%d\n", (ret-(pip->ip_hl * 4)), (src_buff), (inet_ntoa(pip->ip_dst)), (p_recvicmp->icmp_seq), (pip->ip_ttl));
        } else {
            printf("[myping]recv no wanted packet!\n");
            continue;
        }

    }

    printf("done!\n");
    close(recvfd);
    close(sockfd);
    return PING_SUCCESS;
}

wireshark抓包结果:

相关推荐
梅见十柒10 分钟前
wsl2中kali linux下的docker使用教程(教程总结)
linux·经验分享·docker·云原生
Koi慢热13 分钟前
路由基础(全)
linux·网络·网络协议·安全
传而习乎23 分钟前
Linux:CentOS 7 解压 7zip 压缩的文件
linux·运维·centos
soulteary25 分钟前
突破内存限制:Mac Mini M2 服务器化实践指南
运维·服务器·redis·macos·arm·pika
alphaTao26 分钟前
LeetCode 每日一题 2024/11/18-2024/11/24
算法·leetcode
我们的五年33 分钟前
【Linux课程学习】:进程程序替换,execl,execv,execlp,execvp,execve,execle,execvpe函数
linux·c++·学习
kitesxian35 分钟前
Leetcode448. 找到所有数组中消失的数字(HOT100)+Leetcode139. 单词拆分(HOT100)
数据结构·算法·leetcode
爱吃青椒不爱吃西红柿‍️1 小时前
华为ASP与CSP是什么?
服务器·前端·数据库
IT果果日记1 小时前
ubuntu 安装 conda
linux·ubuntu·conda
Python私教1 小时前
ubuntu搭建k8s环境详细教程
linux·ubuntu·kubernetes