1
  1. soc = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); 在客户端,运行时,得到 == -1 错误

  2. 如果accept函数只能与UDP和TCP更高的协议一起使用,如何接受多个客户端进行二层通信?

在哪里可以找到接受函数的代码,我想为第 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 通信的情况下,您不需要接受。这同样可以扩展到链路层 (L2) 帧,即每一方都可以随意发送或接收,而无需先实际建立连接。

这应该使用 root 来完成

于 2012-09-15T09:54:12.360 回答