Linux——实现客户端与服务器的无阻塞通信

编写程序,实现客户端与服务器的无阻塞交互,提交程序源码、运行结果截图。

//server.c

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

#define SERV_PORT 3333
//#define SERV_IP_ADDR "192.168.0.129"
#define BACKLOG 5
#define MAXSIZE 100

void* send_data(void* temp1)
{
	int fd1=(int)temp1;
	char sbuf[MAXSIZE];
	
	while(1)
	{
		bzero(sbuf,MAXSIZE);
		fgets(sbuf,MAXSIZE-1,stdin);
		send(fd1,sbuf,strlen(sbuf),0);
	}
	return (void*)0;
}

void* recv_data(void* temp2)
{
	int fd2=(int)temp2;
	char rbuf[MAXSIZE];
	int length;
	
	while(1)
	{
		bzero(rbuf,MAXSIZE);
		length = recv(fd2,rbuf,sizeof(rbuf),0);
		rbuf[length] = '\0';
		if(strncmp(rbuf,"close",5)==0)
		{
			printf("over\n");
			break;
		}
		else
		{
			printf("%s\n",rbuf);
		}
	}
	return (void*)0;
}

int main()
{   
    int sfd,sin_size,new_fd;
	struct sockaddr_in serv_addr;//服务器地址信息
	struct sockaddr_in client_addr;//客户端地址信息
    
	//1.创建服务器端套接字sfd
	sfd = socket(AF_INET,SOCK_STREAM,0);
	
	 /*优化: 允许绑定地址快速重用 */
     int b_reuse = 1;
     setsockopt (sfd, SOL_SOCKET, SO_REUSEADDR, &b_reuse, sizeof (int));
	
    //2.将sfd与服务器端的IP地址和端口号绑定
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_port = htons(SERV_PORT);
	serv_addr.sin_addr.s_addr = INADDR_ANY;
	//serv_addr.sin_addr.s_addr = inet_addr(SERV_IP_ADDR);
	bzero(&(serv_addr.sin_zero),8);
	
	bind(sfd,(struct sockaddr*)&serv_addr,sizeof(struct sockaddr));
    
	//3.开启监听
	listen(sfd,BACKLOG);
	
	while(1)
	{
		//4.与客户端建立连接
		sin_size = sizeof(struct sockaddr_in);
		new_fd = accept(sfd,(struct sockaddr*)&client_addr,&sin_size);
	
		printf("Receive a connection from %s\n",inet_ntoa(client_addr.sin_addr));
	
		//5.向客户端发送一条消息
		send(new_fd,"Hello,you are conneceted!\n",26,0);
		
		pthread_t thA,thB;	
		pthread_create(&thA,NULL,send_data,(void*)new_fd);
		pthread_create(&thB,NULL,recv_data,(void*)new_fd);
		pthread_join(thA,NULL);
		pthread_join(thB,NULL);
		
		close(new_fd);
	}	
	return 0;
}


//client.c


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

#define SERV_PORT 3333
#define MAXDATASIZE 100 /*每次最大数据传输量*/

int main(int argc, char *argv[])
{
   int cfd, recvbytes; // cfd 数据传输socket
   char buf[MAXDATASIZE];
   struct hostent *host;
   struct sockaddr_in serv_addr; //TCP/IP 协议的地址结构

   if (argc < 2)
   {
      fprintf(stderr,"Please enter the server's hostname!\n");
      exit(1);
   }
   
   if ((host=gethostbyname(argv[1]))==NULL) 
    //用域名或主机名获取IP 地址,可以直接输入IP 地址
    {
       perror("gethostbyname 出错!");
       exit(1);
    }
    if ((cfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)//创建套接字
    {
        perror("socket 创建出错!");
        exit(1);
     }
    
    serv_addr.sin_family=AF_INET; //表示TCP/IP 协议
    serv_addr.sin_port=htons(SERV_PORT); /*16 位端口号,网络字节顺序*/
    serv_addr.sin_addr = *((struct in_addr *)host->h_addr); /*32 位服务器IP 地址,网络字节顺序*/
    bzero(&(serv_addr.sin_zero),8); /*保留*/
     
    if (connect(cfd, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr)) == -1)// 建立连接, 连接的serv_addr 为保存服务器地址的结构体
     {
           perror("connect error!");
           exit(1);
     }

     if ((recvbytes=recv(cfd, buf, MAXDATASIZE, 0)) ==-1) //接收数据
      {
          perror("recv 出错!");
          exit(1);
      }
      buf[recvbytes] = '\0';
      printf("Received: %s",buf);
       close(cfd); //关闭socket
      return 0;
}

PS:

结合线程基本知识,实现客户端与服务器的无阻塞交流。

(1)服务器代码清单 

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

#define SERVPORT 3333 //服务器监听端口号
#define BACKLOG 5 //最大同时连接请求数
#define MAXDATASIZE 100 /*每次最大数据传输量*/

void *senddata(void * arg)
{
	int client_fd = (int)arg;
	char sbuf[100];

	while (1)
	{
		memset(sbuf, 0, sizeof(sbuf) / sizeof(char));
		scanf("%s", sbuf);
		/*子进程代码段*/
		//往客户端发送消息
		if (send(client_fd, sbuf, 26, 0) == -1)
		{
			perror("send\n");
		}
		if (strncmp(sbuf, "close", 5) == 0)
		{
			printf("server send close msg\n");
			break;
		}
	}
	return (void *)0;
}

void *recvdata(void *arg)
{
	int client_fd = (int)arg;
	char buf[MAXDATASIZE];

	while (1)
	{
		memset(buf, 0, sizeof(buf) / sizeof(char));
		if ((recv(client_fd, buf, sizeof(buf), 0)) == -1) {
			perror("recv\n");
		}
		printf("server receives information %s \n ", buf);
		if (strncmp(buf, "close", 5) == 0)
		{
			printf("will close client\n");
			break;
		}
	}
	return (void *)0;
}

int main()
{
	int sockfd, client_fd, sin_size;//sockfd:服务器 socket,client_fd:客户端  socket
	char buf[MAXDATASIZE];
	struct sockaddr_in my_addr;//本机地址信息
	struct sockaddr_in remote_addr;//客户端地址信息*

	if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
	{
		perror("socket\n");
		exit(1);
	}
	/*优化 4:允许绑定地址快速重用   */
	int b_reuse = 1;
	setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &b_reuse, sizeof(int));
	my_addr.sin_family = AF_INET;
	my_addr.sin_port = htons(SERVPORT);
	my_addr.sin_addr.s_addr = INADDR_ANY;//表示监听任何地址
	bzero(&(my_addr.sin_zero), 8);
	//将本机地址与建立的套接字号进行绑定
	if (bind(sockfd, (struct sockaddr*)&my_addr, sizeof(struct sockaddr)) == -1)
	{
		perror("bind\n");
		exit(1);
	}
	//开始监听
	if (listen(sockfd, BACKLOG) == -1)
	{
		perror("listen\n");
		exit(1);
	}

	while (1)
	{
		sin_size = sizeof(struct sockaddr_in);
		//接收客户端的连接
		if ((client_fd = accept(sockfd, (struct sockaddr*)&remote_addr, &sin_size)) == -1)
		{
			perror("accept\n");
			// continue;
		}
		printf("Receive a connection from %s\n", inet_ntoa(remote_addr.sin_addr));
		pthread_t t1, t2;
		pthread_create(&t1, NULL, senddata, (void *)client_fd);
		pthread_create(&t2, NULL, recvdata, (void *)client_fd);
		pthread_join(t1, NULL);
		pthread_join(t2, NULL);
		close(client_fd);
		printf("test main\n");
	}
}
close(sockfd);
return 0;

(2)客户端代码清单 

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

#define SERVPORT 3333
#define MAXDATASIZE 100 /*每次最大数据传输量*/

void *senddata(void * arg)
{
	int sockfd = (int)arg;
	char sbuf[100];
	while (1)
	{
		memset(sbuf, 0, sizeof(sbuf) / sizeof(char));
		scanf("%s", sbuf);
		/*子进程代码段*/
		//往客户端发送消息
		if (send(sockfd, sbuf, 26, 0) == -1)
		{
			perror("send\n");
		}
		if (strncmp(sbuf, "close", 5) == 0)
		{
			printf("client send close msg\n");
			break;
		}
	}
	return (void *)0;
}

void *recvdata(void *arg)
{
	int sockfd = (int)arg;
	char buf[MAXDATASIZE];
	while (1)
	{
		memset(buf, 0, sizeof(buf) / sizeof(char));
		if ((recv(sockfd, buf, sizeof(buf), 0)) == -1) {
			perror("recv\n");
		}
		printf("client receives information %s \n ", buf);

		if (strncmp(buf, "close", 5) == 0)
		{
			printf("client will close\n");
			break;
		}
	}
	return (void *)0;
}

int main(int argc, char *argv[])
{
	int sockfd, recvbytes; // sockfd数据传输   socket
	//char buf[MAXDATASIZE];
	struct hostent *host;
	struct sockaddr_in serv_addr; //TCP/IP协议的地址结构

	if (argc < 2)
	{
		fprintf(stderr, "Please enter the server's hostname!\n");
		exit(1);
	}
	if ((host = gethostbyname(argv[1])) == NULL)
		//用域名或主机名获取 IP地址,可以直接输入  IP地址
	{
		perror("gethostbyname出错!");
		exit(1);
	}
	if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)//创建套接字
	{
		perror("socket创建出错!");
		exit(1);
	}
	serv_addr.sin_family = AF_INET; //表示 TCP/IP协议
	serv_addr.sin_port = htons(SERVPORT); /*16位端口号,网络字节顺序*/
	serv_addr.sin_addr = *((struct in_addr *)host->h_addr); /*32位服务器  IP地址,网络字节顺序*/
	bzero(&(serv_addr.sin_zero), 8); /*保留*/
	//建立连接,连接的    serv_addr为保存服务器地址的结构体
	if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr)) == -1)
	{
		perror("connect error!");
		exit(1);
	}
	//printf("Receive a connection from %s\n",inet_ntoa(remote_addr.sin_addr));
	pthread_t t1, t2;
	pthread_create(&t1, NULL, senddata, (void *)sockfd);
	pthread_create(&t2, NULL, recvdata, (void *)sockfd);
	pthread_join(t1, NULL);
	pthread_join(t2, NULL);
	close(sockfd);
	printf("test main\n");
	return 0;
}

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值