当前位置: 技术问答>linux和unix
多线程ping程序出现“段错误”,求解
来源: 互联网 发布时间:2017-05-22
本文导语: 本程序主要实现同时测量到多个地址的延时值,用多线程实现。本程序在ipv4和ipv6环境下均适用,但主要目的是在ipv6环境下测时延。以下显示代码是程序的核心部分,但运行有错误,求高手相助! //initial 初始化 //s...
本程序主要实现同时测量到多个地址的延时值,用多线程实现。本程序在ipv4和ipv6环境下均适用,但主要目的是在ipv6环境下测时延。以下显示代码是程序的核心部分,但运行有错误,求高手相助!
//initial 初始化
//send 发包
//recv 收包
//proc 处理包,即取包中的数据,计算延时并显示
void *initialsendrecvproc( struct addrinfo *ai )
{//为方便查找错误,本函数进行了简化,去掉了循环
//只发一个ping包,然后接收该ping包的返回包
//最后计算这两个包的时间差,并输出该时间差值
int size;
int nsent;
char recvbuf[BUFSIZE];
char controlbuf[BUFSIZE];
struct msghdr msg;
struct iovec iov;
ssize_t n;
struct timeval tval;
struct proto *pr;
if (ai->ai_family == AF_INET) { //ipv4
pr = &proto_v4;
#ifdef IPV6
} else if (ai->ai_family == AF_INET6) { //ipv6
pr = &proto_v6;
if (IN6_IS_ADDR_V4MAPPED(&(((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr)))
err_quit("cannot ping IPv4-mapped IPv6 address");
#endif
} else
err_quit("unknown address family %d", ai->ai_family);
pr->sasend = ai->ai_addr;
pr->sarecv = Calloc(1, ai->ai_addrlen);
pr->salen = ai->ai_addrlen;
sockfd = Socket(pr->sasend->sa_family, SOCK_RAW, pr->icmpproto); //使用原始套接字
setuid(getuid());
if (pr->finit)
(*pr->finit)( );
nsent = 0;
size = 60 * 1024;
setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));//设置套接字选项
iov.iov_base = recvbuf;
iov.iov_len = sizeof(recvbuf);
msg.msg_name = pr->sarecv;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = controlbuf;
send_v6(pr, &nsent); //发一个包
msg.msg_namelen = pr->salen;
msg.msg_controllen = sizeof(controlbuf);
n = recvmsg(sockfd, &msg, 0);//收上面刚发的包
Gettimeofday(&tval, NULL);//得到当前时间
proc_v6(recvbuf, n, &msg, &tval, pr);//处理包,计算延时并显示
//标记1 printf(“hjn”);
pthread_exit(NULL);
}
int main(int argc, char **argv)
{
int i;
struct addrinfo *ai;
char *h;
//ipaddress是一个纯文本文件,为排错方便,文件里只包含两行字符串
//第一行是”www.google.com” 第二行是”www.kame.net”
if ((fp1 = fopen("ipaddress","r")) == NULL)
{
printf("cannot open infilen");
exit(0);
}
while(!feof(fp1))
{
fscanf(fp1,"%s",host); //host的定义语句为 char host[100]
ai = Host_serv(host, NULL, 0, 0);
h = Sock_ntop_host(ai->ai_addr, ai->ai_addrlen);
printf("PING %s (%s): %d data bytesn", ai->ai_canonname ? ai->ai_canonname : h, h, datalen);
memset(&thread, 0, sizeof(thread));
if (( pthread_create(&thread, NULL, initialsendrecvproc(ai), NULL)) != 0)
{
printf("thread %d create fail!n", i++);
}
else
{
printf("thread %d create success!n", i++);
}
//标记2 printf(“hjn”);
sleep(1);
//标记3 printf(“hjn”);
}
}
程序想达到的效果是启两个线程,分别测试到www.google.com和www.kame.net 的延时,但以上程序执行的结果如下:
[ root@ipv6measure hj]# gcc dxcpingipv6.c –o dxcpingipv6 –lpthread –lunp –g
[ root@ipv6measure hj]# chmod u+s dxcpingipv6
[ root@ipv6measure hj]# ./dxcpingipv6
PING www.google.com (2404:6800:4005:801::1013): 56 data bytes
64 bytes from 2404:6800:4005:801::1013: seq=0, hlim=49, rtt=287.707 ms
[ root@ipv6measure hj]#
也就是说第一个线程启动成功了,但第一个线程执行完了以后,整个程序就结束了。Main线程不再继续往下执行了,第二个线程也没有被创建。
我在标记1处添加了一行printf(“hjn”);结果程序运行结果如下
[ root@ipv6measure hj]# ./dxcpingipv6
PING www.google.com (2404:6800:4005:805::1011): 56 data bytes
64 bytes from 2404:6800:4005:805::1011: seq=0, hlim=49, rtt=294.230 ms
hj
[ root@ipv6measure hj]#
这说明线程函数initialsendrecvproc(ai)能正常执行结束,那为什么第一个线程执行完了以后,整个程序就结束了?main线程为什么不再继续往下执行了?求高手指点!
我尝试对程序作了一点修改,把标记1和标记1下面一行”pthread_exit(NULL);”注释掉了,重新运行程序,结果如下
[ root@ipv6measure hj]# ./dxcpingipv6
PING www.google.com (2404:6800:4005:803::1014): 56 data bytes
64 bytes from 2404:6800:4005:803::1014: seq=0, hlim=49, rtt=295.691 ms
thread 0 create success!
段错误
[ root@ipv6measure hj]#
这说明第一个线程启动后,main线程开始继续往下执行了,但出现了”段错误”。
为确定”段错误”在哪一行产生的,我在标记2处加了一行printf(“hjn”);结果程序运行结果如下
[ root@ipv6measure hj]# ./dxcpingipv6
PING www.google.com (2404:6800:4005:800::1010): 56 data bytes
64 bytes from 2404:6800:4005:800::1010: seq=0, hlim=49, rtt=279.224 ms
thread 0 create success!
hj
段错误
[ root@ipv6measure hj]#
也就是说程序能执行完标记2这一行,然后报”段错误”
我进一步修改,把标记2这一行注释掉,在标记3处加一行printf(“hjn”);结果程序运行结果如下
[ root@ipv6measure hj]# ./dxcpingipv6
PING www.google.com (2404:6800:4005:803::1010): 56 data bytes
64 bytes from 2404:6800:4005:803::1010: seq=0, hlim=49, rtt=284.096 ms
thread 0 create success!
段错误
[ root@ipv6measure hj]#
这说明程序没有运行到标记3这一行就报”段错误”了!也就是说”段错误”出现在标记2行和标记3行之间,也就是sleep(1)这条语句处!但执行sleep(1)怎么会报”段错误”呢?求高手指点!
//initial 初始化
//send 发包
//recv 收包
//proc 处理包,即取包中的数据,计算延时并显示
void *initialsendrecvproc( struct addrinfo *ai )
{//为方便查找错误,本函数进行了简化,去掉了循环
//只发一个ping包,然后接收该ping包的返回包
//最后计算这两个包的时间差,并输出该时间差值
int size;
int nsent;
char recvbuf[BUFSIZE];
char controlbuf[BUFSIZE];
struct msghdr msg;
struct iovec iov;
ssize_t n;
struct timeval tval;
struct proto *pr;
if (ai->ai_family == AF_INET) { //ipv4
pr = &proto_v4;
#ifdef IPV6
} else if (ai->ai_family == AF_INET6) { //ipv6
pr = &proto_v6;
if (IN6_IS_ADDR_V4MAPPED(&(((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr)))
err_quit("cannot ping IPv4-mapped IPv6 address");
#endif
} else
err_quit("unknown address family %d", ai->ai_family);
pr->sasend = ai->ai_addr;
pr->sarecv = Calloc(1, ai->ai_addrlen);
pr->salen = ai->ai_addrlen;
sockfd = Socket(pr->sasend->sa_family, SOCK_RAW, pr->icmpproto); //使用原始套接字
setuid(getuid());
if (pr->finit)
(*pr->finit)( );
nsent = 0;
size = 60 * 1024;
setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));//设置套接字选项
iov.iov_base = recvbuf;
iov.iov_len = sizeof(recvbuf);
msg.msg_name = pr->sarecv;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = controlbuf;
send_v6(pr, &nsent); //发一个包
msg.msg_namelen = pr->salen;
msg.msg_controllen = sizeof(controlbuf);
n = recvmsg(sockfd, &msg, 0);//收上面刚发的包
Gettimeofday(&tval, NULL);//得到当前时间
proc_v6(recvbuf, n, &msg, &tval, pr);//处理包,计算延时并显示
//标记1 printf(“hjn”);
pthread_exit(NULL);
}
int main(int argc, char **argv)
{
int i;
struct addrinfo *ai;
char *h;
//ipaddress是一个纯文本文件,为排错方便,文件里只包含两行字符串
//第一行是”www.google.com” 第二行是”www.kame.net”
if ((fp1 = fopen("ipaddress","r")) == NULL)
{
printf("cannot open infilen");
exit(0);
}
while(!feof(fp1))
{
fscanf(fp1,"%s",host); //host的定义语句为 char host[100]
ai = Host_serv(host, NULL, 0, 0);
h = Sock_ntop_host(ai->ai_addr, ai->ai_addrlen);
printf("PING %s (%s): %d data bytesn", ai->ai_canonname ? ai->ai_canonname : h, h, datalen);
memset(&thread, 0, sizeof(thread));
if (( pthread_create(&thread, NULL, initialsendrecvproc(ai), NULL)) != 0)
{
printf("thread %d create fail!n", i++);
}
else
{
printf("thread %d create success!n", i++);
}
//标记2 printf(“hjn”);
sleep(1);
//标记3 printf(“hjn”);
}
}
程序想达到的效果是启两个线程,分别测试到www.google.com和www.kame.net 的延时,但以上程序执行的结果如下:
[ root@ipv6measure hj]# gcc dxcpingipv6.c –o dxcpingipv6 –lpthread –lunp –g
[ root@ipv6measure hj]# chmod u+s dxcpingipv6
[ root@ipv6measure hj]# ./dxcpingipv6
PING www.google.com (2404:6800:4005:801::1013): 56 data bytes
64 bytes from 2404:6800:4005:801::1013: seq=0, hlim=49, rtt=287.707 ms
[ root@ipv6measure hj]#
也就是说第一个线程启动成功了,但第一个线程执行完了以后,整个程序就结束了。Main线程不再继续往下执行了,第二个线程也没有被创建。
我在标记1处添加了一行printf(“hjn”);结果程序运行结果如下
[ root@ipv6measure hj]# ./dxcpingipv6
PING www.google.com (2404:6800:4005:805::1011): 56 data bytes
64 bytes from 2404:6800:4005:805::1011: seq=0, hlim=49, rtt=294.230 ms
hj
[ root@ipv6measure hj]#
这说明线程函数initialsendrecvproc(ai)能正常执行结束,那为什么第一个线程执行完了以后,整个程序就结束了?main线程为什么不再继续往下执行了?求高手指点!
我尝试对程序作了一点修改,把标记1和标记1下面一行”pthread_exit(NULL);”注释掉了,重新运行程序,结果如下
[ root@ipv6measure hj]# ./dxcpingipv6
PING www.google.com (2404:6800:4005:803::1014): 56 data bytes
64 bytes from 2404:6800:4005:803::1014: seq=0, hlim=49, rtt=295.691 ms
thread 0 create success!
段错误
[ root@ipv6measure hj]#
这说明第一个线程启动后,main线程开始继续往下执行了,但出现了”段错误”。
为确定”段错误”在哪一行产生的,我在标记2处加了一行printf(“hjn”);结果程序运行结果如下
[ root@ipv6measure hj]# ./dxcpingipv6
PING www.google.com (2404:6800:4005:800::1010): 56 data bytes
64 bytes from 2404:6800:4005:800::1010: seq=0, hlim=49, rtt=279.224 ms
thread 0 create success!
hj
段错误
[ root@ipv6measure hj]#
也就是说程序能执行完标记2这一行,然后报”段错误”
我进一步修改,把标记2这一行注释掉,在标记3处加一行printf(“hjn”);结果程序运行结果如下
[ root@ipv6measure hj]# ./dxcpingipv6
PING www.google.com (2404:6800:4005:803::1010): 56 data bytes
64 bytes from 2404:6800:4005:803::1010: seq=0, hlim=49, rtt=284.096 ms
thread 0 create success!
段错误
[ root@ipv6measure hj]#
这说明程序没有运行到标记3这一行就报”段错误”了!也就是说”段错误”出现在标记2行和标记3行之间,也就是sleep(1)这条语句处!但执行sleep(1)怎么会报”段错误”呢?求高手指点!
|
谢谢分享啊啊