Linux C Socket多线程编程

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信息

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值