NetWork-socket

工作倒是写了不少的socket程序,还蛮有意思的,有必要总结一下

1.        socket函数类型总结

socket函数类型图

 

SOCK_DGRAM就是UDPSOCK_STREAM就是TCP

SOCK_RAW下面会提到

 

如果创建socket时指定为AF_UNIXAF_UNIX宏与旧版的AF_LOCAL等同)时就为linux内部的socket,仅限于同一台计算机内的socket进程通讯,他使用的地址结构是struct sockaddr_un

而如果指定为AF_INET时则为unixlinux的网络socket,使用的数据结构则是struct sockaddr_in

      

 

不管是sockaddr_un/AF_UNIX还是sockaddr_in/AF_INETIPlocalhost的时候,由于可以使用localhost环回地址,数据不用经过物理网卡,多个的话,就用port不同来区别

 

2.        socket服务器处理方式

循环服务器(最普通那种)

并发服务器(就是每一个链接一个线程),下面代码功能是:这个线程做一个server,另外做一个clientclient连接过来后有一个终端窗口,因为很多进程都是后台运行的,有了终端窗口方便调试用的,在工作中很适用的功能,这里就是连接起一个线程

/*

* Function:    dbg_server

* Purpose:    for debug server 

* Arguments:

* Returns:

*/

void dbg_server(void* arg)

{

    int serv_fd;

    int conn_fd;

    struct sockaddr_un serv_addr;

    int rc;

    pthread_t pid;

    char cmd[100];

    if ((serv_fd = socket(AF_UNIX, SOCK_STREAM, NULL)) == -1)

    {

        perror("socket");

        return;

    }

    bzero(&serv_addr, sizeof(serv_addr));

    serv_addr.sun_family = AF_UNIX;

 

    unlink(arg);/* if exit delete it */

    strcpy(serv_addr.sun_path, arg);

 

    if (bind(serv_fd, (struct sockaddr *) &serv_addr, sizeof(struct sockaddr)) == -1)

    {

        perror("bind");

        return;

    }

 

    if (listen(serv_fd, 100) == -1)

    {

        perror("listen");

        return;

    }

    for (; ;)

    {

        conn_fd = accept(serv_fd, NULL, NULL);

        printf("accept conn_addr:0x%x/n", conn_fd);

        rc = pthread_create(&pid, NULL, (void *) &dbg_client,

                (void *) &conn_fd);

        if (rc < 0)

        {

            printf("error pthread_create/n");

            return;

        }

    }

}

 

并发多路复用,在UT通信产品中板卡间通信中用到的,这个是写的一份和上面同样的功能,对比不停的创建线程或者进程而言,更值得推荐

       

/*

* Function:    dbg_server1

* Purpose:    for debug server       

* Arguments:

* Returns:

*/

void dbg_server1(void* arg)

{

    struct sockaddr_un serv_addr;

    struct sockaddr_un conn_addr; 

 

    int serv_fd, i, maxfd, conn_fd, n, clie_num = 0;

 

    fd_set allset;

    socklen_t conn_len;

    char buf[1500];

 

    int rc;

    char cmd[100];   

 

    for (i = 0; i < FD_SETSIZE; i++)

    {

        clib_ipc_data[i].clie_fd = -1;

    }

 

    if ((serv_fd = socket(AF_UNIX, SOCK_STREAM, NULL)) == -1)

    {

        perror("socket");

    }

    bzero(&serv_addr, sizeof(serv_addr));

    serv_addr.sun_family = AF_UNIX;

 

    unlink(arg);/* if exit delete it */

    strncpy(serv_addr.sun_path, arg, sizeof(serv_addr.sun_path) - 1);//strcpy(serv_addr.sun_path, arg);

 

    if (bind(serv_fd, (struct sockaddr_un *) &serv_addr, sizeof(serv_addr)) == -1)

    {

        perror("bind");

    }

 

    if (listen(serv_fd, 100) == -1)

    {

        perror("listen");

    }

 

    FD_ZERO(&allset);

    if (serv_fd != -1)

    {

        FD_SET(serv_fd, &allset);

    }

    maxfd = serv_fd;

    conn_len = sizeof(conn_addr);

    for (; ;)

    {

        rc = select(maxfd + 1, &allset, NULL, NULL, NULL);

        if (rc < 0)

        {

            perror("select");

            exit(1);

        }

        if (FD_ISSET(serv_fd, &allset))

        {

            conn_fd = accept(serv_fd, (struct sockaddr_un *) &conn_addr,

                        &conn_len);

            printf("accept conn_addr/n");

            for (i = 0; i < FD_SETSIZE; i++)

            {

                if (clib_ipc_data[i].clie_fd == -1)

                {

                    clib_ipc_data[i].clie_fd = conn_fd;

                    clib_ipc_data[i].out = fdopen(conn_fd, "r+");

                    FD_SET(conn_fd, &allset);

                    if (clie_num < (i + 1))

                    {

                        clie_num = i + 1;

                    }

                    break;

                }

            }

            if (conn_fd > maxfd)

            {

                maxfd = conn_fd;

            }

        }

        for (i = 0; i < clie_num; i++)

        {

            if (clib_ipc_data[i].clie_fd != -1)

            {

                if (FD_ISSET(clib_ipc_data[i].clie_fd, &allset))

                {

                    rc = read(clib_ipc_data[i].clie_fd, buf, 1500);

                    printf("buffer %s/n", buf);

                    printf("write msg to client:0x%x/n", i);

                    cli_debug(buf);

                }

            }

        }

    }

}

       

2.6提供了效率更高的epool,和select方式很像,但是多了一个epoll_event的结构来记录client的信息,我用linux自带的ab命令建50个连接测试,没感觉到效率有多大提高,那些网络公司的研究这个应该比较深

3.        SOCK_RAW

 

sockfd=socket(PF_PACKET,SOCK_RAW,protocol)

sockfd=socket(PF_PACKET,SOCK_DGRAM,protocol)

SOCK_RAW SOCK_DGRAM类型套接字使用一种与设备无关的标准物理层地址结构sockaddr_ll,但具体操作的报文格式不同。        SOCK_RAW套接字直接14+20+*

SOCK_DGRAM套接字就没有那个14,只有20+*

因为telnetftp等密码都是明文的,所以可以linsniffer这个小工具抓到密码的,记得网卡一定要设置为混杂模式,下面是最主要的一段的代码

int openintf(char *d)

{

   int fd;

   struct ifreq ifr;

   int s;

   fd=socket(PF_PACKET, SOCK_RAW, ETH_P_IP);

    /* 嵌套类型设置,并且只要IP包,如果是ETH_P_ALL就是所有的包 */

   if(fd < 0)

   {

      perror("cant get SOCK_PACKET socket");

      exit(0);

   }

   strcpy(ifr.ifr_name, d);

   s=ioctl(fd, SIOCGIFFLAGS, &ifr);

   if(s < 0)

   {

      close(fd);

      perror("cant get flags");

      exit(0);

   }

   ifr.ifr_flags |= IFF_PROMISC;

   s=ioctl(fd, SIOCSIFFLAGS, &ifr);

    /*网卡设置为混杂模式,只有这样才可以抓包括网络头在内的包 */

   if(s < 0) perror("cant set promiscuous mode");

   return fd;

}

所以现在比较推荐的连接是SSH,服务器端生成一个用户的私钥,拷贝出来,用putty之类的,加载这个私钥,直接连接服务器,协议没研究过,毕竟是加密的数据,服务器端应该需要解密的算法吧

tcpdump也是基于SOCK_RAW来实现的,早的linux版本还用 fd=socket(AF_INET, SOCK_PACKET, htons(0x800));这样的用法已经被fd=socket(PF_PACKET, SOCK_RAW, htons(0x800));替代了

 

4.        小结

其实一直疑惑那些网站后台都是怎么设计的呢?后台也是用select的吗?如果成千上万的连接,select支持最多句柄FD_SETSIZE也就1024啊?不知道N多的服务器之间是怎么建立起来的

 

你可能感兴趣的:(NetWork-socket)