socket线程应用

来源:互联网 发布:天竺棉和水洗棉 知乎 编辑:程序博客网 时间:2024/05/21 14:05

声明:本博文用于学习总结及工作心得


server端:

#include <stdio.h>#include <stdlib.h>#include <sys/types.h>#include <sys/socket.h>#include <string.h>#include <errno.h>#include <unistd.h>#include <netinet/in.h>#include <arpa/inet.h>#include <pthread.h>//改写inet_ntoavoid sockaddr_toa(struct sockaddr_in *addr, char *IPAddr){unsigned char *p = (unsigned char *)&(addr->sin_addr.s_addr);sprintf(IPAddr, "%u.%u.%u.%u", p[0], p[1], p[2], p[3]);}pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;int status = 0;struct ps{int socket;pthread_t *t;};//接收客户端的socket数据的线程void *recvsocket(void *arg){struct ps *p = (struct ps *)arg;int st = p->socket;pthread_t t = *(p->t);char s[1024];char *ip = malloc(sizeof(char) *64);//得到远端sockaddrmemset(ip, 0, sizeof(ip));struct sockaddr_in client_addr;socklen_t client_len = sizeof(client_addr);memset(&client_addr, 0, client_len);getpeername(st, (struct sockaddr *)&client_addr, &client_len);sockaddr_toa(&client_addr, ip);printf("远端sockaddr:%s\n", ip);//得到自身的sockaddrmemset(ip, 0, sizeof(ip));struct sockaddr_in server_addr;socklen_t server_len = sizeof(server_addr);memset(&server_addr, 0, server_len);getsockname(st, (struct sockaddr *)&server_addr, &server_len);sockaddr_toa(&server_addr, ip);printf("自身sockaddr:%s\n", ip);while(1){memset(s, 0, sizeof(s));int rc = recv(st, s, sizeof(s), 0);if(rc <= 0)//如果recv小于等于0 代表socket已经关闭或者出错了{break;}else{printf("client:%s\n", s);}}pthread_mutex_lock(&mutex);status--;pthread_mutex_unlock(&mutex);pthread_cancel(t);//被cancel的线程内部没有使用锁return NULL;}void *sendsocket(void *arg)//向client端socket发送数据{int st = *((int *)arg);char s[1024];while(1){memset(s, 0, sizeof(s));read(STDIN_FILENO, s, sizeof(s));//读取用户输入信息send(st, s, strlen(s), 0);}return NULL;}//第二套int main(int arg, char *args[]){    if (arg < 2) {        return -1;    }    int port = atoi(args[1]);int st = socket(AF_INET, SOCK_STREAM, 0);int on =1;//设置socket属性,第三个参数SO_REUSEADDR代表地址可重用if(setsockopt(st, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1){printf("setsockopt failed %s\n", strerror(errno));return EXIT_FAILURE;}struct sockaddr_in addr;memset(&addr, 0, sizeof(addr));addr.sin_family = AF_INET;//设置结构地址类型为TCP/IP地址addr.sin_port = htons(port);//指定一个端口号 8900 htons: 将short类型从host字节类型到net字节类型的转化addr.sin_addr.s_addr = htonl(INADDR_ANY);//INADDR_ANY代表这个server上所有的地址//将IP与server程序绑定if(bind(st, (struct sockaddr *)&addr, sizeof(addr)) == -1){printf("bind failed %s\n", strerror(errno));return EXIT_FAILURE;}//server开始listenif(listen(st, 20) == -1){printf("listen failed %s\n", strerror(errno));return EXIT_FAILURE;}int client_st = 0; //client端socketstruct sockaddr_in client_addr;//表示client段的IP地址pthread_t thrd1, thrd2;struct ps p1, p2;while(1){memset(&client_addr, 0, sizeof(client_addr));socklen_t len = sizeof(client_addr);//accept会阻塞,直到有客户端连接过来,accept返回client的socket描述符//client_st = accept(st, p, &len);client_st = accept(st, (struct sockaddr *)&client_addr, &len);pthread_mutex_lock(&mutex);//为全局变量加一个互斥锁,放在与线程函数同时读写变量的冲突status ++;pthread_mutex_unlock(&mutex);//解锁if(status > 1)//当client端连接数大于1时,断开以后的连接{close(client_st);continue;}if(client_st == -1){printf("accept failed %s\n", strerror(errno));return EXIT_FAILURE;}        printf("accept by %s\n", inet_ntoa(client_addr.sin_addr));        p1.socket = client_st;        p1.t = &thrd1;        p2.socket = client_st;        p2.t = &thrd2;        pthread_create(&thrd1, NULL, recvsocket, (void *)&p1);        pthread_detach(thrd1);//设置线程可分离        pthread_create(&thrd2, NULL, sendsocket, (void *)&p2);        pthread_detach(thrd2);//设置线程可分离}    close(st);//关闭server端listen的socket    return EXIT_SUCCESS;}

client端:

#include <stdio.h>#include <stdlib.h>#include <sys/types.h>#include <sys/socket.h>#include <string.h>#include <errno.h>#include <unistd.h>#include <netinet/in.h>#include <arpa/inet.h>#include <pthread.h>//接收客户端的socket数据的线程void *recvsocket(void *arg){int st = *((int *)arg);char s[1024];while(1){memset(s, 0, sizeof(s));int rc = recv(st, s, sizeof(s), 0);if(rc <= 0)//如果recv小于等于0 代表socket已经关闭或者出错了{break;}else{printf("client:%s\n", s);}}return NULL;}void *sendsocket(void *arg)//向client端socket发送数据{int st = *((int *)arg);char s[1024];while(1){memset(s, 0, sizeof(s));read(STDIN_FILENO, s, sizeof(s));//读取用户输入信息send(st, s, strlen(s), 0);}return NULL;}//第二套int main(int arg, char *args[]){    if (arg < 3) {        return -1;    }        char *ipv4 = args[1];    int port = atoi(args[2]);int st = socket(AF_INET, SOCK_STREAM, 0);//初始化socketif(st == -1){printf("create socket error:%s\n", strerror(errno));return -1;}struct sockaddr_in addr;//定义一个IP地址的结构memset(&addr, 0 , sizeof(addr));addr.sin_family = AF_INET;//设置结构地址类型为TCP/IP地址addr.sin_port = htons(port);//指定一个端口号 8900 htons: 将short类型从host字节类型到net字节类型的转化addr.sin_addr.s_addr = inet_addr(ipv4);//将字符串类型的IP地址转化为int,赋给addr结构成员//调用connect连接到结构addr指定的IP地址和端口号if(connect(st, (struct sockaddr *)&addr, sizeof(addr)) == -1){printf("connect failed %s\n", strerror(errno));return -1;}pthread_t thrd1, thrd2;pthread_create(&thrd1, NULL, recvsocket, (void *)&st);pthread_create(&thrd2, NULL, sendsocket, (void *)&st);pthread_join(thrd1, NULL);//pthread_join(thrd2, NULL);close(st);//关闭socketreturn EXIT_SUCCESS;}

makefile:

.SUFFIXES:.c .oCC=gccSRCS1=socket.cSRCS2=server.cOBJS1=$(SRCS1:.c=.o)OBJS2=$(SRCS2:.c=.o)EXEC1=socketEXEC2=serverstart: $(OBJS1) $(OBJS2)$(CC) -o $(EXEC1) $(OBJS1) -lpthread$(CC) -o $(EXEC2) $(OBJS2) -lpthread@echo '-----------OK-----------'.c.o:$(CC) -Wall -g -o $@ -c $<clean:rm -rf $(OBJS1) $(ONJS2)





0 0
原创粉丝点击