本文共 10774 字,大约阅读时间需要 35 分钟。
设置套接字函数:
#includeint setsockopt(int sockfd, int level, int optname, const void* optval, socklen_t* optlen);//sockfd要设置的目的套接字//level套接字的控制层次//optname optval optlen是三个相关的参数,通过不同的搭配可以设置不同的功能
应用:
1.数据收发时限设置
struct timeva timeout;timeout.tv_sec=5;timeout.tv_usec=0;//接受时限setsockopt(serversocket, SQL_SOCKET,SO_RCVTIMEO, (char*)&timeout,sizeof(timeout));//发送时限setsockopt(serversocket, SQL_SOCKET,SO_SNDTIMEO, (char*)&timeout,sizeof(timeout));
2.修改收发缓冲区
//接收缓冲区int opt=1024*1024;setsockopt(serversocket, SQL_SOCKET, SO_RCVBUF, (const char*)&opt,sizeof(opt));//发送缓冲区setsockopt(serversocket, SQL_SOCKET, SO_SNDBUF, (const char*)&opt,sizeof(opt));
3.广播设置
int bBroadcast=1;setsockopt(seversocket, SQL_SOCKET, SO_BROADCAST,(cosnt char*)&bBroadcast,sizeof(bBroadcast));
4.直接数据复制
为了提升系统性能,在发送或接受数据时,可以主动设置数据不经历由缓冲区到套接字缓存区的拷贝。
int opt=0;setsockopt(serversocket, SQL_SOCKET,SO_SNDBUF,(char*)&opt,sizeof(opt));setsockopt(serversocket, SQL_SOCKET,SO_RCVBUF,(char*)&opt,sizeof(opt));
Select技术:
#include#include #include #include #include #include #include #include #include #define SERVER_PORT 5555#define QUEUE_LENGTH 5#define BUF_SIZE 200int main(int argc, char **argv){ int server_socket,new_socket; struct sockaddr_in server_addr,client_addr; socklen_t sin_size; int client_socket[QUEUE_LENGTH]; int conn_num; int yes=1; char buf[BUF_SIZE]; int ret; int i; //创建套接字 if((server_socket=socket(AF_INET,SOCK_STREAM,0))<0){ perror("Socket"); return 0; } //设置为可重复使用 if(setsockopt(server_socket,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int))==-1){ perror("setsockopt"); return 0; } //设置服务器地址信息设置 server_addr.sin_family=AF_INET; //TCP server_addr.sin_port=htons(SERVER_PORT); server_addr.sin_addr.s_addr=INADDR_ANY; //本地IP地址 memset(server_addr.sin_zero,'\0',sizeof(server_addr.sin_zero)); //绑定套接字与地址信息 if(bind(server_socket,(struct sockaddr*)&server_addr,sizeof(server_addr))==-1){ perror("setsockopt"); return 0; } //侦听 if(listen(server_socket,5)==-1){ perror("setsockopt"); return 0; } printf("listen port : %d\n",SERVER_PORT); fd_set clientfdset; int maxsock; struct timeval tv; conn_num=0; sin_size=sizeof(client_addr); maxsock=server_socket; while(1){ //初始化,清空并添加服务器套接字到集合 FD_ZERO(&clientfdset); FD_SET(server_socket,&clientfdset); //设置超时时间 tv.tv_sec=15; tv.tv_usec=0; //添加连接的客户端到集合 for(i=0;i maxsock) maxsock=new_socket; } else{ send(new_socket,"sorry overload!",sizeof("sorry overload!"),0); close(new_socket); break; } } } for(i=0;i
原始套接字技术:
原始套接字是一种套接字底层技术,它工作在网络层。利用原始套接字可以完成如下功能。
原始套接字可用于木马中的通信模块,伪造IP地址,拒绝服务攻击,数据包嗅探。
原始套接字的创建:
int rawsock=socket(AF_INET, SOCK_RAW, htons(ETH_P_IP));//可以获取IP层的所有数据报文 htons参数的可选值及其意义
协议码 | 协议名 |
IPPROTO_ICMP | ICMP协议 |
ETH_P_IP | IP协议 |
IPPROTO_TCP | TCP协议 |
IPPROTO_UDP | UDP协议 |
IPPROTO_IPV6 | IPv6协议 |
IPPROTO_EGP | EGP协议 |
数据发送:
在原始套接字中,执行数据发送前要条用setsocketopt函数进行套接字的首部设定:
int opt;setsockopt(sockfd,IPPROTO_IP, IP_HDRINCL, &opt, sizeof(opt));
例子:
//利用原始套接字实现一个简单的采集网络数据包,并进行反向解析IP,MAC地址 #include#include #include #include #include #include #define BUFFER_MAX 2048int main(int argc, char **argv){ int rawsock; char buffer[BUFFER_MAX]; char *ethhead; char *iphead; char *phead; //创建原始套接字 if((rawsock=socket(PF_PACKET,SOCK_RAW,htons(ETH_P_IP)))<0){ printf("error:create raw socket!\n"); exit(0); } long framecount =0; while(1){ int readnum = recvfrom(rawsock,buffer,2048,0,NULL,NULL); if(readnum<42){ printf("error:header is incomplete!\n"); exit(0); } ethhead=(char*)buffer; phead=ethhead; int ethernetmask=0XFF; framecount++; printf("---------------AnalysisiPacket[%d]---------------\n",framecount); printf("MAC:"); int i=6; for(;i<=11;i++) printf("%.2X:",phead[i]ðernetmask); printf("------->"); for(i=0;i<=5;i++) printf("%.2X:",phead[i]ðernetmask); printf("\n"); iphead=ethhead+14; phead=iphead+12; printf("IP:"); for(i=0;i<=3;i++){ printf("%d",phead[i]ðernetmask); if(i!=3) printf("."); } printf("------->"); for(i=4;i<=7;i++){ printf("%d",phead[i]ðernetmask); if(i!=7) printf("."); } printf("\n"); int prototype=(iphead+9)[0]; phead=iphead+20; printf("Protocol:"); switch(prototype){ case IPPROTO_ICMP: printf("ICMP\n"); break; case IPPROTO_IGMP: printf("IGMP\n"); break; case IPPROTO_IPIP: printf("IP"); break; case IPPROTO_TCP: printf("TCP|source port: %u |",(phead[0]<<8)&0XFF00|phead[1]&0XFF); printf("destport: %u\n",(phead[2]<<8)&0XFF00|phead[3]&0XFF); break; case IPPROTO_UDP: printf("UDP|source port: %u |",(phead[0]<<8)&0XFF00|phead[1]&0XFF); printf("destport: %u\n",(phead[2]<<8)&0XFF00|phead[3]&0XFF); break; case IPPROTO_RAW: printf("RAW\n"); break; default: printf("Unkown\n"); } printf("-----------------end--------------------"); } return 0;}
广播技术:
ARP(Address Resolution Protocol)和NTP(Network Time Protocol)都属于广播通信。
ARP是局域网中的地址解析协议,利用这个协议,可以找出IP地址到MAC地址的映射关系。当主机A准备与主机B通信时,如果只知道主机B的IP地址,则主机A向整个全网发送一个ARP请求,询问IP地址为XXXX的主机,如果主机B收到就会产生回应。
NTP是网络时间协议。在支持广播的局域网中设置NTP协议,可以使NTP服务器每隔一个固定的时间间隔,就向全网发送时间信息,客户端在收到时间信息后进行更新处理。
原理解析:
要进行广播通信,首先要理解广播地址。在IP地址中,如果最后一个数字是255,则一定是一个广播地址。
广播要采用UDP的方式,具体流程如下:
例子:
//bserver.c#include#include #include #include #include #include #include #define BUFFSIZE 200#define PORT 5050int main(int argc, char **argv){ int serversocket; struct sockaddr_in serveraddress,clientaddress; int so_broadcast=1; if((serversocket=socket(AF_INET,SOCK_DGRAM,0))<0){ perror("socket"); return 0; } if(setsockopt(serversocket,SOL_SOCKET,SO_BROADCAST,&so_broadcast,sizeof(so_broadcast))<0){ perror("setsockopt"); return 0; } serveraddress.sin_family=AF_INET; serveraddress.sin_port=htons(INADDR_ANY); serveraddress.sin_addr.s_addr=htonl(INADDR_BROADCAST); if(bind(serversocket,(struct sockaddr*)&serveraddress,sizeof(struct sockaddr))<0){ perror("bind"); return 0; } clientaddress.sin_family=AF_INET; clientaddress.sin_port=htons(PORT); clientaddress.sin_addr.s_addr=htonl(INADDR_BROADCAST); while(1){ char buf[BUFFSIZE]; printf("please input your word:"); scanf("%s",buf); if(sendto(serversocket,buf,strlen(buf),0,(struct sockaddr*)&clientaddress,sizeof(clientaddress))<0){ perror("sendto"); return 0; } else printf("send msg: %s\n",buf); } return 0;}
//bclient.c#include#include #include #include #include #include #include int main(int argc, char **argv){ int clientsocket; struct sockaddr_in serveraddress,clientaddress; clientsocket=socket(AF_INET,SOCK_DGRAM,0); serveraddress.sin_family=AF_INET; serveraddress.sin_port=htons(5050); serveraddress.sin_addr.s_addr=htonl(INADDR_ANY); int opt=1; if(setsockopt(clientsocket,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt))<0){ perror("setsockopt"); return 0; } if(bind(clientsocket,(struct sockaddr*)&serveraddress,sizeof(struct sockaddr))!=0){ perror("bind"); return 0; } char buf[200]; while(1){ memset(buf,0,200); int size=0; size=recvfrom(clientsocket,buf,200,0,(struct sockaddr*)&serveraddress,sizeof(serveraddress)); buf[size]='\0'; printf("IP:%s msg:%s\n",inet_ntoa(clientaddress.sin_addr),buf); if(strcmp(buf,"quit")==0){ printf("system quit!\n"); close(clientsocket); return 0; } } return 0;}
组播技术:
组播可以实现小范围内的互联,在发送者和每一个接受者之间时间点对多点的网络连接,是广播通信的一种变种。
根据IP地址的规定,D类地址为组播地址,其网络号为固定的1110,第4到31位定义了某一特殊的组播地址,范围为244.0.0.0~239.255.255.255。其中244.0.0.0~244.0.0.255的地址,它们大多是为了特殊的目的保留的,不建议使用。
套接字的基本属性:组播参数对应5个参数,通过setsockopt设置
//加入组播int setsockopt(client_socket,IPPROTO_IP,IP_ADD_MEMBERSHIP,&multiaddress,sizeof(multiaddress))//退出组播int setsockopt(client_socket,IPPROTO_IP,IP_DROP_MEMBERSHIP,&multiaddress,sizeof(multiaddress))//这里有一个重要的参数multiaddress,结构:struct ip_mreq{ struct in_addr imr_multiaddr; //组播地址 struct in_addr imr_interface; //IPv4地址}
主要流程:
例子:
//memberServer.c#include#include #include #include #include #include #include #include int main(int argc, char **argv){ int server_socket; struct sockaddr_in address; //创建UDP server_socket=socket(AF_INET,SOCK_DGRAM,0); if(server_socket<0){ perror("socket"); return 0; } //初始化多播地址 memset(&address,0,sizeof(address)); address.sin_family=AF_INET; address.sin_port=htons(5555); address.sin_addr.s_addr=inet_addr("224.0.1.100"); //发送信息 while(1){ char buf[200]; printf("input your word:"); scanf("%s",buf); if(sendto(server_socket,buf,sizeof(buf),0,(struct sockaddr*)&address,sizeof(address))<0){ perror("sendto"); return 0; } } return 0;}
//memberClient.c#include#include #include #include #include #include #include #include int main(int argc, char **argv){ struct ip_mreq mreq; int serveraddress_len; int client_socket; struct sockaddr_in serveraddress; //初始化地址 memset(&serveraddress,0,sizeof(serveraddress)); serveraddress.sin_family=AF_INET; serveraddress.sin_port=htons(5555); serveraddress.sin_addr.s_addr=htonl(INADDR_ANY); if((client_socket=socket(AF_INET,SOCK_DGRAM,0))<0){ perror("client"); return 0; } //绑定SOCKET if(bind(client_socket,(struct sockaddr*)&serveraddress,sizeof(serveraddress))<0){ printf("bind"); return 0; } int opt=1; if(setsockopt(client_socket,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt))<0){ printf("setsockopt1"); return 0; } //加入多播 mreq.imr_multiaddr.s_addr=inet_addr("244.0.1.100"); mreq.imr_interface.s_addr=htonl(INADDR_ANY); if(setsockopt(client_socket,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq))<0){ perror("setsockopt2"); return 0; } while(1){ char buf[200]; serveraddress_len=sizeof(serveraddress); if(recvfrom(client_socket,buf,200,0,(struct sockaddr*)&serveraddress,(socklen_t *)serveraddress_len)<0){ perror("recvfrom"); } printf("msg from server: %s\n",buf); if(strcmp(buf,"quit")==0){ if(setsockopt(client_socket,IPPROTO_IP,IP_DROP_MEMBERSHIP,&mreq,sizeof(mreq))<0){ perror("setsokopt3"); } close(client_socket); return 0; } } return 0;}
本文 由 创作,采用 进行许可。欢迎转载,请注明出处: 转载自: