- 論壇徽章:
- 0
|
最近在做實驗,一個程序中創(chuàng)建兩個線程同時給一個ip主機發(fā)送模擬TCP數(shù)據(jù)包(只是發(fā)送和接收,不考慮TCP協(xié)議細節(jié)),可是當兩個線程同時發(fā)送時就會產(chǎn)生錯誤,顯示為 Socket Error:Operation not permitted,但是只用其中的一個線程發(fā)送的時候就沒錯,感覺是什么地方?jīng)_突了,但是自己的水平很低,不知道錯誤的原因,也不知道怎么解決,所以請高手指點,先謝謝了,源碼如下:
#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文件產(chǎn)生隨機數(shù)
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()
{//獲得隨機數(shù)
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)
{//連續(xù)發(fā)送數(shù)據(jù)包時相鄰數(shù)據(jù)包之間的時間間隔
int rdtime= new_rand()%range;
return rdtime;
}
inline int randpktnum(int range)
{//一次連續(xù)發(fā)送數(shù)據(jù)包的個數(shù)
int rdnum= new_rand()%range;
return rdnum;
}
inline int wait_to_resendtime(int range)
{//等待下一波數(shù)據(jù)包的時間
int rdnum= new_rand()%range;
return rdnum;
}
inline int randBytes(int range)
{//每個數(shù)據(jù)包中的字節(jié)數(shù),包括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)
{//發(fā)送一串數(shù)據(jù)包
int num=randpktnum( packetsnum );
while(num-->0){
send_tcp(sockfd,saddr,daddr,priority);
usleep(sendpkt_interval(10000));
}
}
void* packet_sender_0()
{//發(fā)包線程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" ;//設(shè)置目的主機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()
{//發(fā)包線程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" ;//設(shè)置目的主機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)
{//發(fā)送優(yōu)先級為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
/*創(chuàng)建線程*/
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)
{
/*等待線程結(jié)束*/
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
這個程序只是想模擬一下網(wǎng)絡(luò)數(shù)據(jù)包的隨機性效果,去掉一個線程源碼就能發(fā)包成功,在另一頭機器上就可以得到,只是開2個線程時就出錯了。望高手相助。 |
|