Linux socket编程(TCP,UDP,RAW)
1、TCP socket编程服务器端程序:TCP_server.c[cpp] viewplaincopy#include #include #include #include #include #include #define SERVPORT 8080
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头部 =不定
更多推荐
所有评论(0)