您的位置:首页 > 理论基础 > 计算机网络

Linux socket编程(TCP,UDP,RAW)

2011-07-25 13:36 435 查看

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头部 =不定
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: