C语言实现服务器客户端通信(互发信息)

  • Post author:
  • Post category:其他


C语言实现服务器客户端通信(互发信息)



客户端

利用select实现

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <strings.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/time.h>
#define SERV_PORT 5001      //5000~65535
#define SERV_IP_ADDR  "192.168.1.94"   //local ip
int main()
{
	int fd=-1;//定义fd备用
	struct sockaddr_in sin;//定义填充结构体备用,强转为sockaddr使用
	
	/*1 create socket fd*/					
	if((fd=socket(AF_INET,SOCK_STREAM,0))<0){//申请文件描述符	
		perror ("socket");
		exit(-1);
	}
	

	/*2.connect with sever net*/
    	bzero(&sin,sizeof(sin));//清零结构体 并给结构体变量赋值
	sin.sin_family=AF_INET;			
	sin.sin_port = htons(SERV_PORT);
	sin.sin_addr.s_addr=inet_addr(SERV_IP_ADDR);

	connect(fd,(struct sockaddr *)&sin,sizeof(sin));//在套接字上启动连接

	/*3 .read write*/
	fd_set rset;//定义一个rset集合用来存放文件描述符
	int maxfd = -1;//定义最大容量
	int ret=-1;
	struct timeval tout;//定义超时结构体
	char buf[BUFSIZ];
	while(1) {
		FD_ZERO(&rset);//清0
		FD_SET(0,&rset);//将标准输入0的文件描述符存入
		FD_SET(fd,&rset);//将网络套接字socket的文件描述符fd存入
		maxfd=fd;//将此时的fd记为最大文件描述符
		tout.tv_sec=5;//超时结构体秒赋值
		tout.tv_usec=0;//超时结构体毫秒赋值
		select(maxfd+1,&rset,NULL,NULL,&tout);// 当调用select()时,由内核根据IO状态修改fd_set的内容,
		//由此来通知执 行了select()的进程哪一Socket或文件可读或可写。主要用于Socket通信当中!
		if(FD_ISSET(0,&rset)) { //标准键盘.上有输入
						//读取键盘输入,发送到网络套接字fd
			bzero(buf,BUFSIZ);
			do {
				ret=read(0,buf,BUFSIZ-1);//读取
			} while(ret<0&&EINTR == errno);
			if(ret < 0) {
				perror("read");		//读取失败 继续
				continue;
			}	
			if (!ret)
				continue;			//读取为空
			if (write(fd,buf,strlen(buf)) <0) {// 将在标准输入读取到的内容 发送(写入)给网络套接字
				perror("write() to socket");
				continue;
			}
			if (!strncasecmp (buf,"quit",4)) { //用户输入了 quit字符
				printf("Client is exiting!\n");
				break;	//接受到quit 退出
		}
		}
		
		
		if(FD_ISSET(fd,&rset)){//服务 器给发送过来了数据
				//读取套接字数据,处理
			bzero(buf,BUFSIZ);
			do{
				ret = read(fd,buf,BUFSIZ-1);//读取网络套接字发送过来的内容
			}while(ret < 0 && EINTR == errno);
			if(ret < 0){
				perror("read from socket");
				continue;
			}
			if(!ret) break; /*服务器关闭*/ 
			//There is a BUG, FIXME! !
			printf("S:---------->%s\n",buf);  //将接受的网络套接字的内容由标准输出 输出
			if (!strncasecmp (buf,"quit",4)) { //用户输入了 quit字符
				printf("Sender Client is exiting!\n");
				break;
			}
		
		}

	}
	/*4 close fd*/
	close(fd);	//关闭网络套接字
	return 0;
}




服务器

这里为了使服务器代码简单,把函数检错移了出来,专门利用一个net.c实现,继而又写了个net.h



net.h

#ifndef __NET_H__
#define __NET_H__
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <strings.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <pthread.h>
#define SERV_PORT 5001 
int ssocket(int domain, int type, int protocol);
int bbind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
int llisten(int sockfd, int backlog);
int aaccept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
int cconnect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);



#endif



net.c

#include "net.h"
int ssocket(int domain, int type, int protocol)
{   
	int sret;
	sret =socket(domain,type,protocol);
	if(sret<0)
		perror("socket");
	else
	   return sret;	
}

int bbind(int sockfd, const struct sockaddr *addr,socklen_t addrlen)
{
	int bret;
	bret=bind(sockfd,addr,addrlen);
	if(bret<0)
		perror("bind");
	else
		return 0;

}


int llisten(int sockfd, int backlog)
{   
	int lret;
	lret=listen(sockfd,backlog);
	if(lret<0)
        perror("bind");
    else
        return 0;
	
}


int aaccept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
{   
	int aret;
again:

	aret=accept(sockfd,addr,addrlen);
	if (aret < 0) {
		if ((errno == ECONNABORTED)||(errno == EINTR)) 
			goto again;
		else
			perror("accept");
		}
   	return aret;
}

int cconnect(int sockfd, const struct sockaddr *addr,socklen_t addrlen)
{   
	int cret;
	connect(sockfd,addr,addrlen);
	if(cret<0)
        perror("connect");
    else
        return 0;

}


最后就是服务器了



server.c

使用了两个线程,分别对应收发

#include "net.h"
#include <strings.h>
#define SRV_PORT 5001
void *do_work(void *arg);
void *do_works(void *arg);

struct s_info{   
	struct sockaddr_in cliaddr;
	int connfd;
};

int main()
{  
	int lfd,cfd;
	pthread_t tid,fid;
	struct sockaddr_in srv_addr,clt_addr;
	socklen_t clt_addr_len;
	clt_addr_len = sizeof(clt_addr);
	srv_addr.sin_family = AF_INET;
	srv_addr.sin_port   = htons(SRV_PORT);
	srv_addr.sin_addr.s_addr = htonl(INADDR_ANY);

	lfd=ssocket(AF_INET,SOCK_STREAM,0);
	int b_reuse=1;
	setsockopt(lfd,SOL_SOCKET,SO_REUSEADDR,&b_reuse,sizeof(int));	
	bbind(lfd,(struct sockaddr *)&srv_addr,sizeof(srv_addr));

	llisten(lfd,128);
	
	struct s_info ts[256];
	int i=0;

	while(1)
	{   

		cfd=aaccept(lfd,(struct sockaddr *)&clt_addr,&clt_addr_len);
		ts[i].cliaddr = clt_addr;
		ts[i].connfd  = cfd;	
		//printf(" 新设备连接ip=%s   线程=%d\n", ntohl(ts[i].cliaddr.sin_addr.s_addr), ts[i].connfd);
		printf(" 新设备线程=%d\n", ts[i].connfd);
		pthread_create(&tid,NULL,do_work,(void* )&ts[i]);
		pthread_create(&fid,NULL,do_works,(void* )&ts[i]);

		pthread_detach(tid);
		  pthread_detach(fid);

		i++;


	}


	return 0;
}



void *do_work(void *arg)
{   
	int n,i;
	struct s_info *ts=(struct s_info *)arg;
	char buf[BUFSIZ];
//	char str[16]="已收到\n";
	while(1)
	{   
		n =read(ts->connfd,buf,BUFSIZ-1);
		if(n==0)
		{	
			printf("exit______\n");	
			exit(1);   
		}
	//	write(1,buf,n);
		printf("C:---------->%s\n",buf);
		bzero(&buf,sizeof(buf));
	}
	close(ts->connfd);
	return (void *)0;

}


void *do_works(void *arg)
{   

    struct s_info *ts=(struct s_info *)arg;
    char strr[BUFSIZ];
    while(1)
    {   
        read(0,strr,BUFSIZ-1);
        write(ts->connfd,strr,BUFSIZ-1);
		bzero(&strr,sizeof(strr));
    }   
    close(ts->connfd);
    return (void *)0;
                                                                                                                                                                                                                   
}











版权声明:本文为weixin_44532706原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。