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
侵权处理: 本个人博客,不盈利,若侵犯了您的作品权,请联系博主删除,莫恶意,索钱财,感谢!