【Linux】linux c语言调用send()接口内核调用流程
1、C语言测试代码:
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <err.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#define BSIZE 0x1000/* "BSIZE" is the size of the buffer we use to read from the socket. */
int main ()
{
struct addrinfo hints, *res;
int socketfd;
char *msg;
int bytes;
char buf[BSIZE+10];
memset (&hints, 0, sizeof(hints));
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;//套接字流方式tcp
/* Get one of the web pages here. //www.lemoda.net*/
socketfd = getaddrinfo ("www.lemoda.net", "http", &hints, &res);//获取主机地址信息
if (socketfd)
{
fprintf (stderr, "%s\n", gai_strerror(socketfd));
exit (1);
}
//建立socket
socketfd = socket (AF_INET, SOCK_STREAM, 0);
if (socketfd < 0)
{
fprintf (stderr, "socket: %s\n", strerror (errno));
exit (1);
}
//链接socket
if (connect(socketfd, res->ai_addr, res->ai_addrlen) < 0)
{
fprintf (stderr, "connect: %s\n", strerror (errno));
close(socketfd);
exit (1);
}
if (socketfd == -1)
exit (1);
/* "format" is the format of the HTTP request we send to the web server. */
const char * format = "GET /%s HTTP/1.0\r\nHost: %s\r\nUser-Agent: fetch.c\r\n\r\n";
asprintf (&msg, format, "momoe/", "www.lemoda.net");
send (socketfd, msg, strlen (msg), 0);
bytes = recvfrom (socketfd, buf, BSIZE, 0, 0, 0);
if (bytes == -1)
{
fprintf (stderr, "%s\n", strerror(errno));
exit (1);
}
buf[bytes] = '\0';
printf ("Get data from remote: \n%s\n", buf);
free (msg);
freeaddrinfo (res);
return 0;
}
2、执行成功后内核打印日志:
完整日志:
p01-network/tcp/kern_2024_11_05_22_04_24_run_test.sh_a.out.log · r77683962/linux-6.9.0-testlog - Gitee.com
基于完整日志过滤" a.out "后的日志,因为第1步c代码编译出来的可执行文件叫a.out,执行时内核中的进程名是a.out
01-network/tcp/kern_2024_11_05_22_04_24_a.out_grep.log · r77683962/linux-6.9.0-testlog - Gitee.com
3、梳理出来的函数调用关系(从系统调用到驱动层):
SYSCALL_DEFINE6(sendto
__sys_sendto
__sock_sendmsg
sock_sendmsg_nosec
netlink_sendmsg
netlink_alloc_large_skb
netlink_unicast
netlink_unicast_kernel
sock_put
netlink_deliver_tap_kernel
netlink_deliver_tap
__netlink_deliver_tap
__netlink_deliver_tap_skb
dev_queue_xmit Y
__dev_queue_xmit Y
__dev_xmit_skb
sch_direct_xmit
dev_hard_start_xmit Y
dev_hard_start_xmit
xmit_one Y
netdev_start_xmit
__netdev_start_xmit
e1000_xmit_frame
4、将第3步的调用关系转换成源代码调用关系:
到这步其实已经到驱动层了。