Linux高度なSocketプログラミング

52758 ワード

ソケット関数を設定するには、次の手順に従います.
#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.直接データコピー
システムのパフォーマンスを向上させるために、データの送信または受信時に、バッファからソケットキャッシュへのデータのコピーを経験しないようにアクティブに設定できます.
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 <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 200



int 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
",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
"); 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
",i); close(client_socket[i]); FD_CLR(client_socket[i],&clientfdset); client_socket[i]=0; } else{ printf("client[%d] msg: %s
",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
",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));
    
    //    IP        
    
    
    htons

    プロトコルコード
    プロトコル名
    IPPROTO_ICMP
    ICMPプロトコル
    ETH_P_IP
    IPプロトコル
    IPPROTO_TCP
    TCPプロトコル
    IPPROTO_UDP
    UDPプロトコル
    IPPROTO_IPV6
    IPv 6プロトコル
    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 2048 int 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!
    "); exit(0); } long framecount =0; while(1){ int readnum = recvfrom(rawsock,buffer,2048,0,NULL,NULL); if(readnum<42){ printf("error:header is incomplete!
    "); exit(0); } ethhead=(char*)buffer; phead=ethhead; int ethernetmask=0XFF; framecount++; printf("---------------AnalysisiPacket[%d]---------------
    ",framecount); printf("MAC:"); int i=6; for(;i<=11;i++) printf("%.2X:",phead[i]&ethernetmask); printf("------->"); for(i=0;i<=5;i++) printf("%.2X:",phead[i]&ethernetmask); printf("
    "); iphead=ethhead+14; phead=iphead+12; printf("IP:"); for(i=0;i<=3;i++){ printf("%d",phead[i]&ethernetmask); if(i!=3) printf("."); } printf("------->"); for(i=4;i<=7;i++){ printf("%d",phead[i]&ethernetmask); if(i!=7) printf("."); } printf("
    "); int prototype=(iphead+9)[0]; phead=iphead+20; printf("Protocol:"); switch(prototype){ case IPPROTO_ICMP: printf("ICMP
    "); break; case IPPROTO_IGMP: printf("IGMP
    "); 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
    ",(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
    ",(phead[2]<<8)&0XFF00|phead[3]&0XFF); break; case IPPROTO_RAW: printf("RAW
    "); break; default: printf("Unkown
    "); } 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.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 5050
    
    
    
    int 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
    ",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
    ",inet_ntoa(clientaddress.sin_addr),buf); if(strcmp(buf,"quit")==0){ printf("system quit!
    "); close(clientsocket); return 0; } } return 0; }

     
    マルチキャスト技術:
    マルチキャストは、小範囲の相互接続を実現することができ、送信者と各受信者との間の時点対多点のネットワーク接続は、ブロードキャスト通信の変種である.
    IPアドレスの規定によると、Dクラスアドレスはマルチキャストアドレスであり、そのネットワーク番号は固定1110であり、4〜31ビット目には244.0.0〜239.255.255.255の特殊なマルチキャストアドレスが定義されている.そのうち244.0.0.0~244.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
    ",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; }