- 论坛徽章:
- 0
|
最近在做实验,一个程序中创建两个线程同时给一个ip主机发送模拟TCP数据包(只是发送和接收,不考虑TCP协议细节),可是当两个线程同时发送时就会产生错误,显示为 Socket Error:Operation not permitted,但是只用其中的一个线程发送的时候就没错,感觉是什么地方冲突了,但是自己的水平很低,不知道错误的原因,也不知道怎么解决,所以请高手指点,先谢谢了,源码如下:
#include <sys/socket.h>
#include <netinet/ip.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include <errno.h>
#include <net/if.h>
#include <unistd.h>
#include <stdio.h>
#include <netdb.h>
#include <pthread.h>
#include <memory.h>
#include <unistd.h>
#include <fcntl.h>
#define ETH_NAME "eth0"
#define DESTPORT 80 //destination port
#define LOCALPORT 6666//local host
#define BUFSIZE 1500//maxsimum bytes in every packet
pthread_t thread[2];
pthread_mutex_t send_mutex,time_mutex;
void send_tcp(int sockfd,struct sockaddr_in *saddr,struct sockaddr_in *daddr,int priority);
unsigned short check_sum(unsigned short *addr,int len);
void init_random()
{//通过urandom文件产生随机数
unsigned int ticks;
struct timeval tv;
int fd;
gettimeofday (&tv, NULL);
ticks = tv.tv_sec + tv.tv_usec;
fd = open ("/dev/urandom", O_RDONLY);
if (fd > 0){
unsigned int r;
int i;
for (i = 0; i < 10240; i++){
read (fd, &r, sizeof (r));
ticks += r;
}
close (fd);
}
srand (ticks);
printf("init finished " ;
}
unsigned int new_rand()
{//获得随机数
int fd;
unsigned int n = 0;
fd = open ("/dev/urandom", O_RDONLY);
if (fd > 0){
read (fd, &n, sizeof (n));
}
close (fd);
return n;
}
inline int sendpkt_interval(int range)
{//连续发送数据包时相邻数据包之间的时间间隔
int rdtime= new_rand()%range;
return rdtime;
}
inline int randpktnum(int range)
{//一次连续发送数据包的个数
int rdnum= new_rand()%range;
return rdnum;
}
inline int wait_to_resendtime(int range)
{//等待下一波数据包的时间
int rdnum= new_rand()%range;
return rdnum;
}
inline int randBytes(int range)
{//每个数据包中的字节数,包括TCP头和IP头,不包括MAC头
int rdnum= new_rand()%range;
return rdnum;
}
void serial_sending(int sockfd,struct sockaddr_in *saddr,struct sockaddr_in *daddr,int priority,int packetsnum)
{//发送一串数据包
int num=randpktnum( packetsnum );
while(num-->0){
send_tcp(sockfd,saddr,daddr,priority);
usleep(sendpkt_interval(10000));
}
}
void* packet_sender_0()
{//发包线程0
int sock0;
struct sockaddr_in saddr;
struct sockaddr_in daddr;
struct hostent *host;
struct ifreq ifr;
int on=1;
bzero(&saddr,sizeof(struct sockaddr_in));
bzero(&daddr,sizeof(struct sockaddr_in));
saddr.sin_family=AF_INET;
daddr.sin_family=AF_INET;
saddr.sin_port=htons(LOCALPORT);
daddr.sin_port=htons(DESTPORT);
host=gethostbyname("192.168.1.4" ;//设置目的主机ip
daddr.sin_addr=*(struct in_addr*)(host-> h_addr_list[0]);
if((sock0=socket(AF_INET,SOCK_RAW,IPPROTO_TCP) )<0)//create a TCP raw socket
{
fprintf(stderr, "Socket Error:%s\n\a ",strerror(errno));
exit(1);
}
strncpy(ifr.ifr_name, ETH_NAME, IFNAMSIZ);
ifr.ifr_name[IFNAMSIZ - 1] = 0;
if (ioctl(sock0, SIOCGIFADDR, &ifr) < 0)//获取本机主机ip
{
perror("ioctl" ;
return;
}
memcpy(&saddr, &ifr.ifr_addr, sizeof(saddr));//保存到saddr中
setsockopt(sock0,IPPROTO_IP,IP_HDRINCL,&on,sizeof(on));//set socket option
setuid(getpid());//no choice,only superuser can use raw socket
while(1){
pthread_mutex_lock(&time_mutex);
sleep(wait_to_resendtime(5));
pthread_mutex_unlock(&time_mutex);
pthread_mutex_lock(&send_mutex);
serial_sending(sock0,&saddr,&daddr,0,300);
pthread_mutex_unlock(&send_mutex);
}
}
void* packet_sender_1()
{//发包线程1
int sock1;
struct sockaddr_in saddr;
struct sockaddr_in daddr;
struct hostent *host;
struct ifreq ifr;
int on=1;
bzero(&saddr,sizeof(struct sockaddr_in));
bzero(&daddr,sizeof(struct sockaddr_in));
saddr.sin_family=AF_INET;
daddr.sin_family=AF_INET;
saddr.sin_port=htons(LOCALPORT);
daddr.sin_port=htons(DESTPORT);
host=gethostbyname("192.168.1.4" ;//设置目的主机ip
daddr.sin_addr=*(struct in_addr*)(host-> h_addr_list[0]);
if((sock1=socket(AF_INET,SOCK_RAW,IPPROTO_TCP) )<0)//create a TCP raw socket
{
fprintf(stderr, "Socket Error:%s\n\a ",strerror(errno));
exit(1);
}
strncpy(ifr.ifr_name, ETH_NAME, IFNAMSIZ);
ifr.ifr_name[IFNAMSIZ - 1] = 0;
if (ioctl(sock1, SIOCGIFADDR, &ifr) < 0)//获取本机主机ip
{
perror("ioctl" ;
return;
}
memcpy(&saddr, &ifr.ifr_addr, sizeof(saddr));//保存到saddr中
setsockopt(sock1,IPPROTO_IP,IP_HDRINCL,&on,sizeof(on));//set socket option
setuid(getpid());//no choice,only superuser can use raw socket
while(1){
pthread_mutex_lock(&time_mutex);
sleep(wait_to_resendtime( );
pthread_mutex_unlock(&time_mutex);
pthread_mutex_lock(&send_mutex);
serial_sending(sock1,&saddr,&daddr,1,300);
pthread_mutex_unlock(&send_mutex);
}
}
void send_tcp(int sockfd,struct sockaddr_in *saddr,struct sockaddr_in *daddr,int priority)
{//发送优先级为priority的包,saddr保存本机ip,daadr保存目的主机ip
char buffer[BUFSIZE]; //for reserving our data packet
struct iphdr *ip;
struct tcphdr *tcp;
int buf_len;
int rdm_data,rdm_wait;
buf_len=sizeof(struct iphdr)+sizeof(struct tcphdr)+randBytes(1000);
memset(buffer,'A',buf_len);
ip=(struct iphdr*)buffer;
ip->version=IPVERSION; //version occupied 4 bits generally
ip->ihl=sizeof(struct ip)>> 2; //length of head of IP packet
ip->tos=priority; //type of service
ip->tot_len=htons(BUFSIZE); //length of IP packet
ip->id=0; //let system fill out this
ip->frag_off=0; //same to above, let's save some time
ip->ttl=MAXTTL; //the longest time 255
ip->protocol=IPPROTO_TCP; //it is TCP that we want to send
ip->check=0; //let system check sum **/
ip->daddr=daddr->sin_addr.s_addr; // the object that we want to assault
tcp= (struct tcphdr*)(buffer + sizeof(struct iphdr));
tcp->source= htons(LOCALPORT); //source port
tcp->dest= daddr->sin_port; //destination port
tcp->seq= random(); //TCP packet sequence
tcp->ack_seq= 0; //TCP packet ack sequence
tcp->doff= 5; //TCP packet data offset
tcp->syn= 1; //I want to establish a connection
tcp->check= 0; //TCP header checksum
ip->saddr=saddr->sin_addr.s_addr;//source ip address
tcp->check=check_sum((unsigned short*)tcp, sizeof(struct tcphdr));
sendto(sockfd,buffer,buf_len,0,(struct sockaddr*)daddr,sizeof(struct sockaddr_in));
}
unsigned short check_sum(unsigned short *addr,int len)
{//校验和
register int nleft=len;
register int sum=0;
register short *w=addr;
short answer=0;
while(nleft>1)
{
sum+=*w++;
nleft-=2;
}
if(nleft==1)
{
*(unsigned char*)(&answer)=*(unsigned char*)w;
sum+=answer;
}
sum=(sum>> 16)+(sum&0xffff);
sum+=(sum>> 16);
answer=~sum;
return(answer);
}
void thread_create(void)
{
int temp;
memset(&thread, 0, sizeof(thread)); //initializing
/*创建线程*/
if((temp = pthread_create(&thread[0], NULL, packet_sender_0, NULL)) != 0) //comment2
printf("creating packet_sender_0 failure!\n" ;
else
printf("creating packet_sender_0 successful!\n" ;
if((temp = pthread_create(&thread[1], NULL, packet_sender_1, NULL)) != 0) //comment3
printf("creating packet_sender_1 failure!\n" ;
else
printf("creating packet_sender_1 successful!\n" ;
}
void thread_wait(void)
{
/*等待线程结束*/
if(thread[0] !=0) {
pthread_join(thread[0],NULL);
printf("thread packet_sender_0 has finished!\n" ;
}
if(thread[1] !=0) {
pthread_join(thread[1],NULL);
printf("thread packet_sender_1 has finished!\n");
}
}
int main()
{
pthread_mutex_init(&send_mutex,NULL);
pthread_mutex_init(&time_mutex,NULL);
printf("main program creating......\n");
thread_create();
printf("main program is waiting for finishing......\n");
thread_wait();
return 0;
}
错误显示为:
main program creating......
creating packet_sender_0 successful!
creating packet_sender_1 successful!
main program is waiting for finishing......
Socket Error:Operation not permitted
这个程序只是想模拟一下网络数据包的随机性效果,去掉一个线程源码就能发包成功,在另一头机器上就可以得到,只是开2个线程时就出错了。望高手相助。 |
|