Linux 网络编程实例(socket–>bind–>listen–>accept)
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)
参考推荐:
Linux网络编程常用函数详解与实例(socket–>bind–>listen–>accept)
TCP端口状态详解 LISTEN、ESTABLISHED、TIME_WAIT、CLOSE_WAIT
Linux 网络错误 TCP: too many orphaned sockets 分析与解决
版权所有: 本文系米扑博客原创、转载、摘录,或修订后发表,最后更新于 2021-01-19 11:00:13
侵权处理: 本个人博客,不盈利,若侵犯了您的作品权,请联系博主删除,莫恶意,索钱财,感谢!