pthread_create是UNIX环境创建线程函数
头文件 #include<pthread.h>
1.pthread_create 函数
int pthread_create(pthread_t *restrict tidp,const pthread_attr_t *restrict_attr,void*(*start_rtn)(void*),void *restrict arg);
返回值
若成功则返回0,否则返回出错编号
参数
第一个参数为指向线程标识符的指针,第二个参数用来设置线程属性,第三个参数是线程运行函数的起始地址, 最后一个参数是运行函数的参数。
2.pthread_join 函数:
int pthread_join(pthread_t thread, void **retval);
第一个参数为被等待的线程标识符,第二个参数为一个用户定义的指针,它可以用来存储被等待线程的返回值。这个函数是一个线程阻塞的函数,调用它的函数将一直等待到被等待的线程结束为止,当函数返回时,被等待线程的资源被收回。如果执行成功,将返回0,如果失败则返回一个错误号。
3、pthread_detach 函数
int pthread_detach(pthread_t tid);
即主线程与子线程分离,子线程结束后,资源自动回收。
4、pthread_exit函数
void pthread_exit(void* retval);
线程通过调用pthread_exit函数终止执行,就如同进程在结束时调用exit函数一样。这个函数的作用是,终止调用它的线程并返回一个指向某个对象的指针。
5.gcc 编译
pthread_create函数编译时报错:undefined reference to 'pthread_create'
原因分析:
由于pthread 库不是 Linux 系统默认的库,连接时需要使用静态库 libpthread.a,所以在使用pthread_create()创建线程,以及调用 pthread_atfork()函数建立fork处理程序时,在编译中要加 -lpthread参数。
解决办法:
在加了头文件#include <pthread.h>之后执行 pthread.c文件,需要使用如下命令:
gcc thread.c -o thread -lpthread
这种情况类似于<math.h>的使用,需在编译时加 -m 参数。
设备1程序,发送5个包UDP给设备2,子线程等待接收数据;设备2会返回5个包UDP
/*
* 主要实现:发送5个文本消息,然后再发送一个stop消息
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include<errno.h>
#include<sys/types.h>
#include<unistd.h>
#include<pthread.h>
int servport=1509;//这里不一样
int sendport=1509;//这里不一样
#define SENDTO_IP "114.55.168.154" //这里不一样
#define ERR_EXIT(m) \
do { \
perror(m); \
exit(EXIT_FAILURE); \
} while (0)
void echo_ser(int sock)//发送5次数据
{
int socket_descriptor; //套接口描述字
int iter=0;
char buf[80];
struct sockaddr_in address;//处理网络通信的地址
bzero(&address,sizeof(address));
address.sin_family=AF_INET;
address.sin_addr.s_addr=inet_addr(SENDTO_IP);
address.sin_port=htons(sendport);
//创建一个 UDP socket
socket_descriptor=socket(AF_INET,SOCK_DGRAM,0);//AF_INET=IPV4 SOCK_DGRAM 数据报套接字(UDP协议)
unsigned int IP_peeraddr = ntohl(address.sin_addr.s_addr);
printf("sendto IP:%d.%d.%d.%d Port:%d\n",(IP_peeraddr>>24)&0xff,(IP_peeraddr>>16)&0xff,(IP_peeraddr>>8)&0xff,IP_peeraddr&0xff,ntohs(address.sin_port));
for(iter=0;iter<=5;iter++)
{
/*
* sprintf(s, "%8d%8d", 123, 4567); //产生:" 123 4567"
* 将格式化后到 字符串存放到s当中
*/
sprintf(buf,"data packet with ID %d\n",iter);
printf("sendto data:data packet with ID %d\n",iter);
/*int PASCAL FAR sendto( SOCKET s, const char FAR* buf, int len, int flags,const struct sockaddr FAR* to, int tolen);
* s:一个标识套接口的描述字。
* buf:包含待发送数据的缓冲区。
* len:buf缓冲区中数据的长度。
* flags:调用方式标志位。
* to:(可选)指针,指向目的套接口的地址。
* tolen:to所指地址的长度。
*/
sendto(sock,buf,sizeof(buf),0,(struct sockaddr *)&address,sizeof(address));
sleep(1);
}
sprintf(buf,"stop\n");
sendto(sock,buf,sizeof(buf),0,(struct sockaddr *)&address,sizeof(address));//发送stop 命令
close(sock);
exit(0);
}
int servsock;
void pthread_recvfrom(void)//接收的线程
{
pthread_detach(pthread_self());//即主线程与子线程分离,子线程结束后,资源自动回收。
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
printf("Waiting for data form sender -->> \n");
char message[256];
struct sockaddr_in sin;
bzero(&sin,sizeof(sin));
//sin.sin_family=AF_INET;
//sin.sin_addr.s_addr=htonl(INADDR_ANY);
//sin.sin_port=htons(port);
int sin_len=sizeof(sin);
while(1){
memset(message, 0, sizeof(message));
int n=recvfrom(servsock,message,sizeof(message),0,(struct sockaddr *)&sin,&sin_len);
if (n <= 0){
printf("recvfrom error");
}else{
printf("----------------------------------------->>\n");
unsigned int IP_peeraddr = ntohl(sin.sin_addr.s_addr);
printf("recvfrom IP:%d.%d.%d.%d Port:%d\n",(IP_peeraddr>>24)&0xff,(IP_peeraddr>>16)&0xff,(IP_peeraddr>>8)&0xff,IP_peeraddr&0xff,ntohs(sin.sin_port));
printf("recvfrom data:%s\n",message);
}
//sleep(2);
}
pthread_exit(0);//函数退出
}
int main(int argc, char** argv) {
//int servsock;
if ((servsock = socket(PF_INET, SOCK_DGRAM, 0)) < 0){
ERR_EXIT("socket error");
}
struct sockaddr_in servaddr;
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(servport);
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(servsock, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0){
ERR_EXIT("bind error");
printf("bind error,port is %d\n",servport);
}else{
printf("bind success,port is %d\n",servport);
}
unsigned int IP_servaddr = ntohl(servaddr.sin_addr.s_addr);
printf("bind IP:%d.%d.%d.%d Port:%d\n",(IP_servaddr>>24)&0xff,(IP_servaddr>>16)&0xff,(IP_servaddr>>8)&0xff,IP_servaddr&0xff,ntohs(servaddr.sin_port));
//````````````````````````` 创建接收的线程
pthread_t getdata_thread;
int ret=pthread_create(&getdata_thread,NULL,(void*)&pthread_recvfrom,NULL);
if(ret!=0){
perror("thread creation failed!\n");
}
//ret=pthread_join(getdata_thread,NULL);//pthread_join()即是子线程合入主线程,主线程阻塞等待子线程结束,然后回收子线程资源。
//if(ret!=0){
//perror("thread join failed!\n");
//}
//`````````````````````````
printf("wait send data -->> \n");
echo_ser(servsock);
return (EXIT_SUCCESS);
}
设备2程序,收到UDP包后,数据原路返回
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<string.h>
#define MYPORT 1509
#define ERR_EXIT(m) \
do { \
perror(m); \
exit(EXIT_FAILURE); \
} while (0)
void echo_ser(int sock)
{
char recvbuf[1024] = {0};
struct sockaddr_in peeraddr;
socklen_t peerlen;
int n;
printf("wait get data from port %d \n",MYPORT);
while (1)
{
peerlen = sizeof(peeraddr);
memset(recvbuf, 0, sizeof(recvbuf));
n = recvfrom(sock, recvbuf, sizeof(recvbuf), 0,(struct sockaddr *)&peeraddr, &peerlen);
if (n <= 0)
{
if (errno == EINTR)
continue;
printf("recvfrom error");
ERR_EXIT("recvfrom error");
}
else if(n > 0)
{
printf("------------------------------------------------------------------------->>\n");
unsigned int IP_peeraddr = ntohl(peeraddr.sin_addr.s_addr);
printf("recvfrom IP:%d.%d.%d.%d Port:%d\n",(IP_peeraddr>>24)&0xff,(IP_peeraddr>>16)&0xff,(IP_peeraddr>>8)&0xff,IP_peeraddr&0xff,ntohs(peeraddr.sin_port));
printf("recvfrom data:%s --->> ",recvbuf);
printf("sendto data:%s\n",recvbuf);
sendto(sock, recvbuf, n, 0,(struct sockaddr *)&peeraddr, peerlen);
}
}
close(sock);
}
int main(void)
{
int sock;
if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0){
ERR_EXIT("socket error");
}
struct sockaddr_in servaddr;
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(MYPORT);
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(sock, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0){
ERR_EXIT("bind error");
printf("bind error,port is %d\n",MYPORT);
}else{
printf("bind success,port is %d\n",MYPORT);
}
unsigned int IP_servaddr = ntohl(servaddr.sin_addr.s_addr);
printf("bind IP:%d.%d.%d.%d Port:%d\n",(IP_servaddr>>24)&0xff,(IP_servaddr>>16)&0xff,(IP_servaddr>>8)&0xff,IP_servaddr&0xff,ntohs(servaddr.sin_port));
echo_ser(sock);
return 0;
}
设备1 Log信息