Linux socket编程(TCP,UDP,RAW)

本文详细介绍了TCP和UDP socket编程的基本概念、服务器端和客户端实现流程,包括socket创建、地址绑定、监听、连接接受、数据收发等关键操作,并通过示例代码展示了如何进行实际操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、TCP socket编程

服务器端程序:TCP_server.c

#include <stdio.h> 
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <string.h>
#include <stdlib.h> 

#define SERVPORT 8080                            	
#define BACKLOG 10                               	/*最大客户端连接数*/ 
#define MAXDATASIZE 100 
int main() { 
    int sockfd,client_fd,addr_size,recvbytes;      	
    char rcv_buf[MAXDATASIZE],snd_buf[MAXDATASIZE];
    char * val;
    struct sockaddr_in server_addr;                    
    struct sockaddr_in client_addr;            		
    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){    
        perror("socket:"); 
        exit(1); 
    } 
    server_addr.sin_family=AF_INET;   
    server_addr.sin_port=htons(SERVPORT);   		
    server_addr.sin_addr.s_addr = INADDR_ANY; 		/*自动探测IP*/
    memset(&(server_addr.sin_zero),0,8); 
    if (bind(sockfd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr))== -1) 
    { 
        perror("bind:"); 
        exit(1); 
    }   
    if (listen(sockfd, BACKLOG) == -1) 
    { 
        perror("listen:"); 
        exit(1); 
    } 
    while(1) 
    {    
        addr_size = sizeof(struct sockaddr_in);    
        if((client_fd=accept(sockfd,(struct sockaddr *)&client_addr,&addr_size))==-1) 
        {                                                /*非阻塞模式*/ 
            perror("accept:"); 
            continue; 
        }    
        printf("connection from:%s\n",(char *)inet_ntoa(client_addr.sin_addr)); 
                                                         /*inet_ntoa不能重载*/   
        if (!fork()) 
        {                                                /*子进程处理客户端连接*/ 
            if ((recvbytes=recv(client_fd, rcv_buf, MAXDATASIZE, 0)) ==-1) 
            { 
                perror("recv:"); 
                exit(1); 
            }         
	    rcv_buf[recvbytes]='\0';
	    printf("recv:%s\n",rcv_buf);

	    *snd_buf='\0';
	    strcat(snd_buf,"welcome");
            if (send(client_fd,snd_buf,strlen(snd_buf), 0) == -1)    
            {
                perror("send:"); 
                exit(1);
            }
	    printf("send:%s\n",snd_buf);

            close(client_fd); 
            exit(1); 
        }    
        close(client_fd);    
    } 
    return 0;                    			/*由于是无限循环监听,所以不关闭sockfd*/ 
} 

客户端程序:TCP_client.c

#include <stdio.h>
#include <stdlib.h> 
#include <sys/socket.h> 
#include <netdb.h>
#include <string.h>

#define SERVPORT 8080 
#define MAXDATASIZE 100 
int main(int argc, char *argv[]) 
{ 
    int sockfd, recvbytes; 
    char rcv_buf[MAXDATASIZE]; 			/*./client 127.0.0.1 hello*/ 
    char snd_buf[MAXDATASIZE]; 
    struct hostent *host; 
    struct sockaddr_in server_addr; 
    if (argc < 3) 
    { 
        printf("Usage:%s [ip address] [any string]\n",argv[0]); 
        return 1; 
    } 
    *snd_buf = '\0';                      	
    strcat(snd_buf,argv[2]);

    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) 
    { 
        perror("socket:");
        exit(1); 
    } 
    server_addr.sin_family=AF_INET; 
    server_addr.sin_port=htons(SERVPORT); 
    inet_pton(AF_INET,argv[1],&server_addr.sin_addr);
    memset(&(server_addr.sin_zero),0,8); 
    if(connect(sockfd,(struct sockaddr *)&server_addr,sizeof(struct sockaddr))==-1) 
    { 
        perror("connect:"); 
        exit(1); 
    } 

    if (send(sockfd,snd_buf,sizeof(snd_buf), 0) == -1)    
    {         
        perror("send:");
        exit(1); 
    }
    printf("send:%s\n",snd_buf); 

    if ((recvbytes=recv(sockfd, rcv_buf, MAXDATASIZE, 0)) ==-1) 
    { 
        perror("recv:"); 
        exit(1); 
    } 
    rcv_buf[recvbytes] = '\0'; 
    printf("recv:%s\n",rcv_buf); 

    close(sockfd); 
    return 0; 
} 

Makefile:

all:TCP_server TCP_client
TCP_server:TCP_server.c
	gcc -o TCP_server TCP_server.c -lpthread
TCP_client:TCP_client.c
	gcc -o TCP_client TCP_client.c
clean:
	rm -f TCP_server
	rm -f TCP_client

2、UDP socket编程

服务器端程序:UDP_server.c

#include <stdio.h> 
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <string.h>
#include <stdlib.h> 
#define SERVPORT 8080                            	
#define MAXDATASIZE 100 
int main() { 
    int sockfd,client_fd,addr_size,recvbytes;      	
    char rcv_buf[MAXDATASIZE],snd_buf[MAXDATASIZE];
    char * val;
    struct sockaddr_in server_addr;                     
    struct sockaddr_in client_addr;            		
    if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1){    
        perror("socket:"); 
        exit(1); 
    } 
    server_addr.sin_family=AF_INET;   
    server_addr.sin_port=htons(SERVPORT);   		
    server_addr.sin_addr.s_addr = INADDR_ANY; 		
    memset(&(server_addr.sin_zero),0,8); 
    if (bind(sockfd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr))== -1) 
    { 
        perror("bind:"); 
        exit(1); 
    }   

    while(1) 
    {    
        addr_size = sizeof(struct sockaddr);    

        if (!fork()) 
        {                                                
            if ((recvbytes=recvfrom(sockfd,rcv_buf,MAXDATASIZE,0,
                                   (struct sockaddr*)&client_addr,&addr_size)) ==-1) 
            { 
                perror("recv:"); 
                exit(1); 
            }
            rcv_buf[recvbytes]='\0';
	    printf("recv:%s\n",rcv_buf);

	    *snd_buf='\0';
	    strcat(snd_buf,"welcome");
            if (sendto(sockfd,snd_buf,strlen(snd_buf),0,
                                   (struct sockaddr*)&client_addr,addr_size) == -1)    
            {
                perror("send:"); 
                exit(1);
            }
	    printf("send:%s\n",snd_buf);
            exit(1); 
        }    
    } 
    close(sockfd);   
    return 0;                    	
} 

客户端程序:UDP_client.c

#include <stdio.h>
#include <stdlib.h> 
#include <sys/socket.h> 
#include <netdb.h>
#include <string.h>

#define SERVPORT 8080 
#define MAXDATASIZE 100 
int main(int argc, char *argv[]) 
{ 
    int server_sockfd, recvbytes,addr_size; 
    char rcv_buf[MAXDATASIZE]; 			/*./client 127.0.0.1 hello*/ 
    char snd_buf[MAXDATASIZE]; 
    struct hostent *host; 
    struct sockaddr_in server_addr; 
    if (argc < 3) 
    { 
        printf("Usage:%s [ip address] [any string]\n",argv[0]); 
        return 1; 
    } 
    *snd_buf = '\0';                      	/*收到的网络数据结尾没有'\0'*/
    strcat(snd_buf,argv[2]);

    if ((server_sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) 
    { 
        perror("socket:");
        exit(1); 
    } 
    server_addr.sin_family=AF_INET; 
    server_addr.sin_port=htons(SERVPORT); 
    inet_pton(AF_INET,argv[1],&server_addr.sin_addr);
    memset(&(server_addr.sin_zero),0,8); 

    addr_size=sizeof(struct sockaddr);
    if (sendto(server_sockfd,snd_buf,sizeof(snd_buf),0,
                          (struct sockaddr*)&server_addr,addr_size) == -1)    
    {         
        perror("send:");
        exit(1); 
    }
    printf("send:%s\n",snd_buf); 

    if ((recvbytes=recvfrom(server_sockfd,rcv_buf,MAXDATASIZE,0,
                         (struct sockaddr*)&server_addr,&addr_size)) ==-1) 
    { 
        perror("recv:"); 
        exit(1); 
    } 
    rcv_buf[recvbytes] = '\0'; 
    printf("recv:%s\n",rcv_buf); 

    close(server_sockfd); 
    return 0; 
} 

Makefile:

all:UDP_server UDP_client
UDP_server:UDP_server.c
	gcc -o UDP_server UDP_server.c 
UDP_client:UDP_client.c
	gcc -o UDP_client UDP_client.c
clean:
	rm -f UDP_server
	rm -f UDP_client

3、raw socket编程

截获ip数据包:         socket(AF_INET, SOCK_RAW, IPPROTO_TCP|IPPROTO_UDP|IPPROTO_ICMP)

截获以太网数据帧:socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP|ETH_P_ARP|ETH_P_ALL))

#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <linux/if_ether.h>
#include <linux/in.h>
#include <stdlib.h>                               /*使用exit函数要添加stdlib.h库*/
#define MAXDATASIZE 2048

int main()
{
        
        int sock, n_read, proto;        
        char buffer[MAXDATASIZE];
        char  *ethhead, *iphead, *tcphead,*udphead, *icmphead, *p;
        
	if((sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP))) < 0)
    	{
		perror("socket:");
        	exit(1);
    	}
        
	while(1) 
	{
     		n_read = recvfrom(sock, buffer, 2048, 0, NULL, NULL);
        	/*
        	14   6(dest)+6(source)+2(type or length)+[数据段尾部2B]
        	+
        	20   ip header=12(其他位)+4(source_ip)+4(dest_ip)[+40(可选项)]
        	+
        	8   icmp(不定),tcp(20~60) or udp(8) header
        	= 42
        	*/
		if(n_read < 42) 
   		{
			perror("Incomplete header, packet corrupt:");
      			continue;
   		}
                
        	ethhead = buffer;
        	p = ethhead;
                printf("MAC: %.2X:%02X:%02X:%02X:%02X:%02X==>"
                           "%.2X:%.2X:%.2X:%.2X:%.2X:%.2X\n",
        		p[6]&0XFF, p[7]&0XFF, p[8]&0XFF, p[9]&0XFF, p[10]&0XFF, p[11]&0XFF,
       			p[0]&0XFF, p[1]&0XFF, p[2]&0XFF,p[3]&0XFF, p[4]&0XFF, p[5]&0XFF);

                iphead = ethhead + 14;  
                p = iphead + 12;
        
           	printf("IP: %d.%d.%d.%d => %d.%d.%d.%d\n",
           	p[0]&0XFF, p[1]&0XFF, p[2]&0XFF, p[3]&0XFF,
           	p[4]&0XFF, p[5]&0XFF, p[6]&0XFF, p[7]&0XFF);
            	proto = (iphead + 9)[0];
            	p = iphead + 20;
             	printf("Protocol:");
            	switch(proto)
              	{
                	case IPPROTO_ICMP: printf("ICMP\n");break;
                	case IPPROTO_IGMP: printf("IGMP\n");break;
                	case IPPROTO_IPIP: printf("IPIP\n");break;
                	case IPPROTO_TCP :
                	case IPPROTO_UDP : 
    				printf("%s,", proto == IPPROTO_TCP ? "TCP": "UDP"); 
    				printf("source port: %u,",(p[0]<<8)&0XFF00 |  p[1]&0XFF);
    				printf("dest port: %u\n", (p[2]<<8)&0XFF00 | p[3]&0XFF);
         			break;
    			case IPPROTO_RAW : printf("RAW\n");break;
    			default:printf("Unkown, please query in include/linux/in.h\n");
        	}
	}
}


raw_socket.c运行后可用ping www.baidu.com测试

4、socket编程总结

(1)raw_socket编程步骤:socket→recvfrom

(2)tcp_socket编程步骤:

          服务器端:socket→初始化struct  sockaddr_in→bind→listen→[accept→send→recv] 

          客户端:    socket→初始化struct  sockaddr_in→connect→[recv→send]

(3)udp_socket编程步骤:

          服务器端:socket→初始化struct  sockaddr_in→bind→[recvfrom→sendto]

          客户端:    socket→初始化struct  sockaddr_in→[sendto→recvfrom]

          注:[]表示循环

(4)网络封包各层报头

          mac层头部+尾部   =14+2

          ip层头部                    =20~60

          tcp头部                      =20~60

          udp头部                    =8

          icmp头部                  =不定

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值