linux socket常用配置

来源:互联网 发布:链轮设计参数计算软件 编辑:程序博客网 时间:2024/06/07 06:26
设置套接字函数:
#include<sys/socket.h>int 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.直接数据复制,接收发送缓存大小配置为0//为了提升系统性能,在发送或接受数据时,可以主动设置数据不经历由缓冲区到套接字缓存区的拷贝。int opt=0;setsockopt(serversocket, SQL_SOCKET,SO_SNDBUF,(char*)&opt,sizeof(opt));setsockopt(serversocket, SQL_SOCKET,SO_RCVBUF,(char*)&opt,sizeof(opt));

例子:

#include <stdio.h>#include <sys/socket.h>#include <unistd.h>#include <stdlib.h>#include <sys/types.h>#include <errno.h>#include <netinet/in.h>#include <arpa/inet.h>#include <string.h>#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<QUEUE_LENGTH;i++){            if(client_socket[i]!=0)                FD_SET(client_socket[i],&clientfdset);        }        //select模式        ret=select(maxsock+1,&clientfdset,NULL,NULL,&tv);        if(ret<0){            perror("select");            break;        }        else if(ret==0){            printf("waiting timeout\n");            continue;        }                //检查集合内是否已经存在        for(i=0;i<conn_num;i++){            if(FD_ISSET(client_socket[i],&clientfdset)){                ret=recv(client_socket[i],buf,sizeof(buf),0);                                if(ret<=0){                    printf("client[%d] close\n",i);                    close(client_socket[i]);                    FD_CLR(client_socket[i],&clientfdset);                    client_socket[i]=0;                }                else{                    printf("client[%d] msg: %s\n",i,buf);                    send(client_socket[i],buf,sizeof(buf),0);                }            }        }                if(FD_ISSET(server_socket,&clientfdset)){            new_socket=accept(server_socket,(struct sockaddr*)&client_addr,&sin_size);            if(new_socket<=0){                perror("accept");                continue;            }            if(conn_num<QUEUE_LENGTH){                client_socket[conn_num++]=new_socket;                printf("new client[%d] %s: %d\n",conn_num,inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port));                if(new_socket>maxsock)                    maxsock=new_socket;            }            else{                send(new_socket,"sorry overload!",sizeof("sorry overload!"),0);                close(new_socket);                break;            }        }    }        for(i=0;i<QUEUE_LENGTH;i++){        if(client_socket[i]!=0)            close(client_socket[i]);    }    }

原始套接字技术:
  原始套接字是一种套接字底层技术,它工作在网络层。利用原始套接字可以完成如下功能。
  设置网卡为混杂模式,嗅探当前网路流经本网卡的所有数据包。
  构造各种数据包(IP,ICMP,TCP,UDP等),并进行发送。
  进行新协议的验证。 
  原始套接字可用于木马中的通信模块,伪造IP地址,拒绝服务攻击,数据包嗅探。

原始套接字的创建:

int rawsock=socket(AF_INET, SOCK_RAW, htons(ETH_P_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 <stdio.h>#include <sys/socket.h>#include <unistd.h>#include <sys/types.h>#include <linux/if_ether.h>#include <linux/in.h>#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,则一定是一个广播地址。
网络广播地址:网络广播地址在没有进行子网划分的网络内广播,由于当强的网络均涉及子网划分,故此种地址很少存在
受限广播地址:以255.255.255.255组成的广播地址,在当前路由器均不转发此类广播
子网广播地址:子网广播地址是一种常用的广播方式,它是指在一个具体的子网内进行广播,比如192.168是网络ID,那么192.168.1.255就是子网192.168.1的广播全部子网广播地址:是指所有子网络的广播,以上一个为例,全部子网广播地址是192.168.255.255
广播要采用UDP的方式,具体流程如下:


创建UDP套接字
设置套接字属性为SO_BROADCAST,设置为广播地址
设置广播地址为INADDR_BROADCAST,同时也要指定发送端口
进行数据收发操作
例子:

//bserver.c#include <sys/types.h>#include <stdio.h>#include <sys/socket.h>#include <stdlib.h>#include <string.h>#include <netdb.h>#include <errno.h>#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 <sys/types.h>#include <stdio.h>#include <sys/socket.h>#include <stdlib.h>#include <string.h>#include <netdb.h>#include <errno.h>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 <stdio.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <netdb.h>#include <unistd.h>#include <stdlib.h>#include <string.h>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 <stdio.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <netdb.h>#include <unistd.h>#include <stdlib.h>#include <string.h>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;}


0 0
原创粉丝点击