netstat

netstat命令是用来显示网络的连接,路由表和接口统计等网络的信息。

netstat有许多的选项,我们常用的选项是 -an 用来显示详细的网络状态

至于其它的选项我们可以使用帮助

# netstat --help
usage: netstat [-vWeenNcCF] [] -r         netstat {-V|--version|-h|--help}
       netstat [-vWnNcaeol] [ 。。。]
       netstat { [-vWeenNac] -I[] | [-veenNac] -i | [-cnNe] -M | -s [-6tuw] } [delay]

        -r, --route              display routing table
        -I, --interfaces=<Iface> display interface table for <Iface>
        -i, --interfaces         display interface table
        -g, --groups             display multicast group memberships
        -s, --statistics         display networking statistics (like SNMP)
        -M, --masquerade         display masqueraded connections

        -v, --verbose            be verbose
        -W, --wide               don't truncate IP addresses
        -n, --numeric            don't resolve names
        --numeric-hosts          don't resolve host names
        --numeric-ports          don't resolve port names
        --numeric-users          don't resolve user names
        -N, --symbolic           resolve hardware names
        -e, --extend             display other/more information
        -p, --programs           display PID/Program name for sockets
        -o, --timers             display timers
        -c, --continuous         continuous listing

        -l, --listening          display listening server sockets
        -a, --all                display all sockets (default: connected)
        -F, --fib                display Forwarding Information Base (default)
        -C, --cache              display routing cache instead of FIB
        -Z, --context            display SELinux security context for sockets

  <Socket>={-t|--tcp} {-u|--udp} {-U|--udplite} {-S|--sctp} {-w|--raw}
           {-x|--unix} --ax25 --ipx --netrom
  <AF>=Use '-6|-4' or '-A <af>' or '--<af>'; default: inet
  List of possible address families (which support routing):
    inet (DARPA Internet) inet6 (IPv6) ax25 (AMPR AX。25) 
    netrom (AMPR NET/ROM) ipx (Novell IPX) ddp (Appletalk DDP) 
    x25 (CCITT X。25) 

 

$ netstat -an

$ netstat -an | head
Active Internet connections (including servers)
Proto Recv-Q Send-Q  Local Address          Foreign Address        (state)    
tcp4       0    517  192。168。31。46。50202    172。217。160。106。443    ESTABLISHED
tcp4       0      0  192。168。31。46。50195    58。251。81。186。443      ESTABLISHED
tcp4       0      0  192。168。31。46。50192    172。217。24。14。443      SYN_SENT   
tcp4       0      0  192。168。31。46。50187    172。217。24。10。443      SYN_SENT   
tcp4       0      0  192。168。31。46。50185    172。217。24。10。443      SYN_SENT   
tcp4       0      0  192。168。31。46。50182    172。217。24。10。443      SYN_SENT   
tcp4       0      0  192。168。31。46。50181    172。217。24。10。443      SYN_SENT   
tcp4       0    517  192。168。31。46。50180    172。217。160。106。443    ESTABLISHED

 

telnet

telnet是一个用来远程控制的程序,但是我们完全可以用这个程序来调试我们的服务端程序的。

比如,我们的服务器程序在监听8888端口,我们可以用telnet localhost 8888来查看服务端的状况。

$ telnet localhost 8086

$ telnet localhost 8086
Trying ::1。。。
telnet: connect to address ::1: Connection refused
Trying ::1。。。
telnet: connect to address ::1: Connection refused
Trying fe80::1。。。
telnet: connect to address fe80::1: Connection refused
Trying 127。0。0。1。。。
Connected to yg-mac。local。
Escape character is '^]'。
Connection closed by foreign host。

 

网络函数描述和实例:

int socket(int domain, int type, int protocol)

1)domain

主机采用的通讯协族(AF_UNIX和AF_INET等)。

AF_UNIX 只能够用于单一的Unix系统进程间通信,

AF_INET 是针对Internet的,因而可以允许在远程主机之间通信,推荐

2)type

我们网络程序所采用的通讯协议(SOCK_STREAM,SOCK_DGRAM等)

SOCK_STREAM 表明我们用的是TCP协议,这样会提供按顺序的,可靠,双向,面向连接的比特流。 推荐

SOCK_DGRAM 表明我们用的是UDP协议,这样只会提供定长的,不可靠,无连接的通信。

3)protocol

由于我们指定了type,所以这个地方我们一般只要用0来代替就可以了

 

socket为网络通讯做基本的准备。成功时返回文件描述符,失败时返回-1,看errno可知道出错的详细情况

int bind(int sockfd, struct sockaddr *my_addr, int addrlen)

1)sockfd: 是由socket调用返回的文件描述符。

2)addrlen: 是sockaddr结构的长度。

3)my_addr: 是一个指向sockaddr的指针, 在中有 sockaddr的定义

struct sockaddr {
    unisgned short as_family;
    char sa_data[14];
};

不过由于系统的兼容性,我们一般不用这个头文件,而使用另外一个结构(struct sockaddr_in) 来代替。

在中有sockaddr_in的定义

struct sockaddr_in {
    unsigned short sin_family;
    unsigned short int sin_port;
    struct in_addr sin_addr;
    unsigned char sin_zero[8];
}

我们主要使用Internet所以

sin_family 一般为AF_INET,

sin_addr 设置为INADDR_ANY表示可以和任何的主机通信,

sin_port 是我们要监听的端口号。

sin_zero[8] 是用来填充的。

bind将本地的端口同socket返回的文件描述符捆绑在一起。成功是返回0,失败的情况和socket一样

 

int listen(int sockfd,int backlog)

sockfd: 是bind后的文件描述符。

backlog: 设置请求排队的最大长度。当有多个客户端程序和服务端相连时, 使用这个表示可以介绍的排队长度。 listen函数将bind的文件描述符变为监听套接字。返回的情况和bind一样。

 

int accept(int sockfd, struct sockaddr *addr,int *addrlen)

sockfd: 是listen后的文件描述符。

addr,addrlen是用来给客户端的程序填写的,服务器端只要传递指针就可以了。

bind,listen和accept是服务器端用的函数,accept调用时,服务器端的程序会一直阻塞到有一个客户程序发出了连接。 accept成功时返回最后的服务器端的文件描述符,这个时候服务器端可以向该描述符写信息了。 失败时返回-1

 

int connect(int sockfd, struct sockaddr * serv_addr,int addrlen)

sockfd: socket返回的文件描述符。

serv_addr: 储存了服务器端的连接信息。其中sin_add是服务端的地址

addrlen: serv_addr的长度

connect 函数是客户端用来同服务端连接的。成功时返回0,sockfd是同服务端通讯的文件描述符失败时返回-1

总的来说,网络程序是由两个部分组成的--客户端和服务器端。

它们的建立步骤一般是:

服务器端  socket-->bind-->listen-->accept

客户端  socket-->connect

 

socket 实例

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>

////////  Server  ////////
int main()
{
    int sockfd, new_fd;
    struct sockaddr_in my_addr;
    struct sockaddr_in their_addr;
    int sin_size;

    // socket 建立TCP套接口
    if((sockfd = socket(AF_INET, SOCK_STREAM, 0))==-1)  // TCP
    {
        printf("create socket error");
        perror("socket");
        exit(1);
    }

    // 初始化结构体,并绑定2323端口
    my_addr.sin_family = AF_INET;
    my_addr.sin_port = htons(2323);
    my_addr.sin_addr.s_addr = INADDR_ANY;
    bzero(&(my_addr.sin_zero),8);

    // bind 绑定套接口
    if(bind(sockfd,(struct sockaddr *)&my_addr, sizeof(struct sockaddr))==-1)
    {
        perror("bind socket error");
        exit(1);
    }

    // listen 创建监听套接口
    if(listen(sockfd, 10)==-1)
    {
        perror("listen");
        exit(1);
    }

    // accept 等待连接
    while(1)
    {
        sin_size = sizeof(struct sockaddr_in);

        printf("server is run.\n");

        // 如果建立连接,将产生一个全新的套接字
        if((new_fd = accept(sockfd,(struct sockaddr *)&their_addr, &sin_size))==-1)
        {
            perror("accept");
            exit(1);
        }
        printf("accept success.\n");

        // 生成一个子进程来完成和客户端的会话,父进程继续监听
        if(!fork())
        {
            printf("create new thred success.\n");
            
            // 读取客户端发来的信息
            int numbytes;
            char buff[256];
            memset(buff,0,256);
            if((numbytes = recv(new_fd, buff, sizeof(buff), 0))==-1)   // recv 接收数据
            {
                perror("recv");
                exit(1);
            }
            printf("%s",buff);

            // 将从客户端接收到的信息再发回客户端
            if(send(new_fd, buff, strlen(buff), 0)==-1)                // send 发送数据
            {
                perror("send");
                close(new_fd);
                exit(0);
            }
        }
        close(new_fd);
    }
    close(sockfd);
}


////////  Client  ////////
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>

int main(int argc,char *argv[])
{
    int sockfd,numbytes;
    char buf[100];

    struct sockaddr_in their_addr;
    // int i = 0;
    // 将基本名字和地址转换
    // he = gethostbyname(argv[1]);

    // socket 建立一个TCP套接口
    if((sockfd = socket(AF_INET, SOCK_STREAM, 0))==-1)      // TCP
    {
        perror("socket");
        printf("create socket error.建立一个TCP套接口失败");
        exit(1);
    }
    // 初始化结构体,连接到服务器的2323端口
    their_addr.sin_family = AF_INET;
    their_addr.sin_port = htons(2323);

    // their_addr.sin_addr = *((struct in_addr *)he->h_addr);
    inet_aton( "127.0.0.1", &their_addr.sin_addr );
    bzero(&(their_addr.sin_zero),8);

    // connect 和服务器建立连接
    if(connect(sockfd,(struct sockaddr *)&their_addr,sizeof(struct sockaddr))==-1)
    {
        perror("connect");
        exit(1);
    }

    // 向服务器发送数据
    if(send(sockfd,"hello!socket.",6,0)==-1)
    {
        perror("send");
        exit(1);
    }
    
    // 接受从服务器返回的信息
    if((numbytes = recv(sockfd,buf,100,0))==-1)
    {
        perror("recv");
        exit(1);
    }
    buf[numbytes] = '\0';
    printf("Recive from server:%s",buf);

    // 关闭socket
    close(sockfd);

    return 0;
}

 

原文: Linux网络编程常用函数详解与实例(socket-->bind-->listen-->accept)

 

 

参考推荐

TCP/IP 协议详解

TCP/IP 数据报格式

TCP/IP 协议头部结构体

Linux socket 常用函数

WebSocket 简介及Nginx配置

Python 实现 socket 通讯(TCP)

Python 实现 socket 通讯(UDP)

Linux网络编程常用函数详解与实例(socket–>bind–>listen–>accept)

TCP端口状态详解 LISTEN、ESTABLISHED、TIME_WAIT、CLOSE_WAIT

Linux 网络错误 TCP: too many orphaned sockets 分析与解决

HTTPS 工作原理

Docker 底层技术详解

Linux curl 命令模拟 POST/GET 请求

CentOS 6/7 配置 sendEmail 发送邮件