1
  1. soc = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); クライアント側で実行すると、== -1 エラーが発生します

  2. 受け入れ機能がUDPおよびTCP上位プロトコルでのみ使用できる場合、レイヤー2通信で複数のクライアントを受け入れる方法は?

受け入れ機能のコードはどこにありますか、レイヤー2用に書き直したいと思います。

更新: soc = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); を試した後 また == -1 、このエラーを取得します

サーバー側とクライアント側の両方が同じコンピューターです。ローカルで奇妙なのは、サーバー側を実行している場合、このエラーはありませんが、クライアントプログラムを実行するとエラーが発生することです

//#include "stdafx.h"

#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h> 
#include <arpa/inet.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <resolv.h>
#include <net/if.h>
#include <netinet/if_ether.h>
#include <netpacket/packet.h>
#include <net/ethernet.h>
#include <netinet/ether.h>
//#include "sock.h"

#define MAX_MESSAGE          21000
#define FD_NUM 5
#define tcp_port                5009


//#pragma comment(lib, "ws2_32.lib")
//#include <winsock2.h>

char host_ip[16] = "127.0.0.1";

void task()
{
    struct sockaddr_in local;
    int opt;
    int soc;

    //soc = socket(AF_INET,SOCK_STREAM,0);
    soc = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
    if (soc==-1) {
        printf("socket error\n");
    }
    // determine ethernet number    
    /*
    struct ifreq ifr;
    size_t if_name_len=strlen(if_name);
    if (if_name_len<sizeof(ifr.ifr_name)) {
        memcpy(ifr.ifr_name,if_name,if_name_len);
        ifr.ifr_name[if_name_len]=0;
    } else {
        printf("interface name is too long");
    }
    if (ioctl(fd,SIOCGIFINDEX,&ifr)==-1) {
        printf("determine ethernet number error\n");
    }
    int ifindex=ifr.ifr_ifindex;
    */
    // mac address
    /*target address*/
    struct sockaddr_ll socket_address;

    /*buffer for ethernet frame*/
    void* buffer = (void*)malloc(ETH_FRAME_LEN);

    /*pointer to ethenet header*/
    unsigned char* etherhead = (unsigned char*)buffer;

    /*userdata in ethernet frame*/
    unsigned char* data = (unsigned char*)buffer + 14;

    /*another pointer to ethernet header*/
    struct ethhdr *eh = (struct ethhdr *)etherhead;

    int send_result = 0;

    /*our MAC address*/
    //10:78:d2:ad:90:cb
    //0x10,0x78,0xD2,0xAD,0x90,0xCB
    unsigned char src_mac[6] = {0x10,0x78,0xD2,0xAD,0x90,0xCB};

    /*other host MAC address*/
    unsigned char dest_mac[6] = {0x10,0x78,0xD2,0xAD,0x90,0xCB};

    /*prepare sockaddr_ll*/

    /*RAW communication*/
    socket_address.sll_family   = PF_PACKET;    
    /*we don't use a protocoll above ethernet layer
      ->just use anything here*/
    socket_address.sll_protocol = htons(ETH_P_IP);  

    /*index of the network device
    see full code later how to retrieve it*/
    socket_address.sll_ifindex  = 0;

    /*ARP hardware identifier is ethernet*/
    socket_address.sll_hatype   = ARPHRD_ETHER;

    /*target is another host*/
    socket_address.sll_pkttype  = PACKET_OTHERHOST;

    /*address length*/
    socket_address.sll_halen    = ETH_ALEN;     
    /*MAC - begin*/
    socket_address.sll_addr[0]  = 0x10;     
    socket_address.sll_addr[1]  = 0x78;     
    socket_address.sll_addr[2]  = 0xD2;
    socket_address.sll_addr[3]  = 0xAD;
    socket_address.sll_addr[4]  = 0x90;
    socket_address.sll_addr[5]  = 0xCB;
    /*MAC - end*/
    socket_address.sll_addr[6]  = 0x00;/*not used*/
    socket_address.sll_addr[7]  = 0x00;/*not used*/

    memcpy((void*)buffer, (void*)dest_mac, ETH_ALEN);
    memcpy((void*)(buffer+ETH_ALEN), (void*)src_mac, ETH_ALEN);
    eh->h_proto = 0x00;

    int j = 0;
    for (j = 46; --j; data[j] = (unsigned char)((int) (255.0*rand()/(RAND_MAX+1.0))));

    /*
    struct sockaddr_in server;
    int len = sizeof(server);
    server.sin_family=AF_INET;
    server.sin_port=htons(5008);
    server.sin_addr.s_addr=inet_addr(host_ip);

    int CONN_SOCK   = InitSocketTcp(tcp_port);
    if(connect(CONN_SOCK, (struct sockaddr*)&server, sizeof(server)) == -1)
    {
        printf("connection failed\n");
    }
    else
    {
            printf("connection ok!\n");
    }
    */
    while(1)
    {
        char buff[492] = "\0";
        printf("input: ");
        scanf("%s", buff);

        //send(CONN_SOCK,buff,strlen(buff),0);
        /*send the packet*/
        send_result = sendto(soc, buff, ETH_FRAME_LEN, 0, (struct sockaddr*)&socket_address, sizeof(socket_address));
        send_result == -1?printf("send error"):0;

        if(buff[0] == 'q')
        {
            //shutdown(CONN_SOCK, SD_SEND);
            //closesocket(CONN_SOCK);
            //WSACleanup();
            close(soc);
            exit(0);
        }
    }
}

int main()
{
    //for(int i=10; i!=0; --i)
        //pthread_create();
    task();
    return 0;
}
4

1 に答える 1

1

Accept()は、接続を確立するため、TCPまたはUDPにのみ使用されます(実際には、主な用途はtcpです)。接続は、tcpの場合に3ウェイハンドシェイクを実行し、シーケンス番号などの情報を交換し、ソケット(ポートとIPアドレス)によって完全に識別されます。

それとは対照的に、udpの場合に通常使用されるように、単にsendtoとreceivefrom apiを使用できます。この場合、各パケットは異なるパスをたどって宛先に到達する可能性があります。udp通信の場合はacceptは必要ありません。同じことをリンクレイヤー(L2)フレームに拡張することもできます。つまり、実際に最初に接続を確立しなくても、各サイドが自由に送信または受信できます。

これはrootを使用して行う必要があります

于 2012-09-15T09:54:12.360 に答える