linux学习笔记18-网络通信socket和多线程

客户端

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>

//接收socket的线程执行函数
void *recv_socket(void *arg)
{
	if(arg == NULL)
	{
		printf("arg is NULL!\n");
		return NULL;
	}
	int sock = *(int *)arg;
	char buf[1024];
	while(1)
	{
	     memset(buf,0,sizeof(buf)); 
	     int msg_len = recv(sock,buf,sizeof(buf),0);  //接收消息
	     if(msg_len > 0)
	     {
		printf("server msg:%s",buf);
	     }
	     else
	     {
	     	break;
	     }
	}
	return NULL;
}
//发送socket的线程执行函数
void *send_socket(void *arg)
{
	if(arg == NULL)
	{
		printf("arg is NULL!\n");
		return NULL;
	}
	int sock = *(int *)arg;
	char buf[1024];
	while(1)
	{
		memset(buf,0,sizeof(buf));
		read(STDIN_FILENO,buf,sizeof(buf));
		send(sock,buf,strlen(buf),0);       //将消息发送
	}
}


int main(int argc,char *argv[])
{
	if(argc < 3)
	{
		printf("argc < 3\n");
		return -1;
	}
	int port = atoi(argv[2]);
	int sock = socket(AF_INET,SOCK_STREAM,0);   //初始化socket
	struct sockaddr_in addr;                    //ip地址结构
	memset(&addr,0,sizeof(addr));               //初始化ip结构
	addr.sin_family = AF_INET;                  //设置结构类型类tcp/ip地址
	addr.sin_port = htons(port);                //指定一个端口号, htons将short类型从host字节类型换net字节类型
	addr.sin_addr.s_addr = inet_addr(argv[1]);  //将ip地址转为int类型数据,赋值给s_addr
	if(connect(sock,(struct sockaddr *)&addr,sizeof(addr)) == -1)
	{
		printf("connect failed:%s\n",strerror(errno));
		return -1;
	}
	
	pthread_t thread1,thread2;
	pthread_create(&thread1,NULL,recv_socket,&sock); //开启线程,执行recv_socket函数
	pthread_create(&thread2,NULL,send_socket,&sock); //开启线程,执行send_socket函数

	pthread_join(thread1,NULL);

	close(sock);
	return 0;
}

服务端(重点在服务端)

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include <pthread.h>

//线程调用只能有一个参数,有多个线程参数的时候,需要用结构体进行封装
struct pthread_socket
{
	int sock;            //socket文件描述符
	pthread_t *thread;    //线程id
};

//接收socket的线程
void *recv_socket(void *argc)
{
	if(argc == NULL)
	{
		printf("recv_socket arg is NULL!\n");
		return NULL;
	}
	struct pthread_socket * ps = (struct pthread_socket *)argc;  //将argc强制转为pthread_socket结构类型的指针

	int sock = ps->sock;
	char buf[1024];
	while(1)
	{
		memset(buf,0,sizeof(buf));
		int rec = recv(sock,buf,sizeof(buf),0);  //接收消息
		if(rec > 0)
		{
			printf("client msg:%s",buf);
		}
		else
		{
			//关闭和出错
			break;
		}
	}
	pthread_cancel(*(ps->thread)); //线程退出的时候,让线程2也退出
	return NULL;
}

//发送socket的线程
void *send_socket(void *argc)
{
	if(argc == NULL)
	{
		printf("send_socket argc is NULL!\n");
		return NULL;
	}
	int sock = *(int *)argc;
	char buf[1024];
	while(1)
	{
		memset(buf,0,sizeof(buf));
		read(STDIN_FILENO,buf,sizeof(buf));
		send(sock,buf,strlen(buf),0);
	}
	return NULL;
}

int main(int argc,char *argv[])
{
	if(argc <2 )
	{
		printf("argc < 2!\n");
		return -1;
	}
	int port = atoi(argv[1]);
	int sock = socket(AF_INET,SOCK_STREAM,0);   //初始化socket

	int on = 1;
	if(setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on)) == -1)
	{
		printf("setscoket failed:%s\n",strerror(errno));
		return -1;
	}

	struct sockaddr_in addr;      //ip地址结构
	memset(&addr,0,sizeof(addr)); //初始化ip结构
	addr.sin_family = AF_INET;    //设置结构类型类tcp/ip地址
	addr.sin_port = htons(port);  //指定一个端口号, htons将short类型从host字节类型换net字节类型 ,将本地字节顺序转换为网络字节顺序
	addr.sin_addr.s_addr = htonl(INADDR_ANY);   //服务器的所有地址
	if(bind(sock,(struct sockaddr *)&addr,sizeof(addr)) == -1) //将ip与server程序绑定
	{
		printf("bind failed:%s\n",strerror(errno));
		return -1;
	}
	if(listen(sock,20) == -1)   //开始监听
	{
		printf("listen failed:%s\n",strerror(errno));
		return -1;
	}

	char buf[1024];
	int  client_sock = 0;
	struct sockaddr_in client_addr;  //表示client的ip地址
	void *p = &client_addr;

	pthread_t pthread1,pthread2;
	
	while(1)
	{
		memset(&client_addr,0,sizeof(client_addr)); 
		int len = sizeof(client_addr);

		client_sock = accept(sock,p,&len); //accept会阻塞,直到客户端连接过来,返回client的socket描述符
		if(client_sock == -1)
		{
			printf("accept failed:%s\n",strerror(errno));
			return -2;
		}
		printf("accept ip:%s\n",inet_ntoa(client_addr.sin_addr));
		struct pthread_socket ps;
		ps.sock = client_sock;
		ps.thread = &pthread2;  //传递线程2 id的地址

		pthread_create(&pthread1,NULL,recv_socket,(void *)&ps);
		pthread_detach(pthread1);                               //分离线程(线程结束后,系统会将线程资源进行回收)
		pthread_create(&pthread2,NULL,send_socket,(void *)&client_sock);
		pthread_detach(pthread2);
		
		//pthread_join(pthread1,NULL);
		//pthread_join(pthread2,NULL);
	}
	close(client_sock);
	close(sock);
	return 0;
}
秋风 2016-12-03