您的位置:首页 > 理论基础 > 计算机网络

TCP 服务器与客户端

2015-08-25 23:53 489 查看

Linux下的TCP服务器与客户端编程都是分步骤来做的,这是一个并发的服务器

代码加注释

服务器端:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sqlite3.h>
#include <signal.h>
#include <time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

/**
	并发服务器,来一个客户端创建一个进程为它服务
*/

/*
	定义一个结构体
*/
typedef struct 
{
	int type; //接受客户请求码 简单设为 1表示返回字符串长度 2表示检查字符串是否有i
	char data[256];   // 接收客户的数据
} MSG;

void do_client(int connfd);

int main()
{
	int connfd, listenfd;//定义连接文件描述符 与 监听描述符
	pid_t pid;//定义进程描述符号
	/*struct sockaddr_in则是internet环境下套接字的地址形式,是结构体
	一般情况下,需要把sockaddr_in结构强制转换成sockaddr结构再传入系统调用函数中。*/
	struct sockaddr_in myaddr;
	/**1、参数domain指明通信域,如PF_UNIX(unix域),PF_INET(IPv4),  
      PF_INET6(IPv6)等  
	   2、type指明通信类型,最常用的如SOCK_STREAM(面向连接可靠方式,  
      比如TCP)、SOCK_DGRAM(非面向连接的非可靠方式,比如UDP)等。
   	   3、参数protocol指定需要使用的协议
	*/
	if((listenfd = socket(PF_INET, SOCK_STREAM, 0)) < 0)
	{
		perror("fail to socket");
		exit(-1);
	}

	bzero(&myaddr,sizeof(myaddr));	//清空数据
	myaddr.sin_family = PF_INET;	//套接字的网络地址
	myaddr.sin_port = htons(atoi("8888"));//端口号
	myaddr.sin_addr.s_addr = inet_addr("127.0.0.1");//ip地址
	//绑定端口号与ip地址   把sockaddr_in结构强制转换成sockaddr结构
	if(bind(listenfd,(struct sockaddr *)&myaddr,sizeof(myaddr)) < 0)
	{
		perror("fail to bind");
		exit(-1);
	}

	//当用户太多时系统为我们保存5个连接等待
	if (listen(listenfd, 5) < 0)
	{
		perror("fail to listen");
		exit(-1);
	}

	printf("------------ Server is running --------\n");
	//当客户段与服务器断开连接时,清理僵尸进程
	signal(SIGCHLD, SIG_IGN);
	while ( 1 )
	{
		//父进程负责与客户端连接,此方法是阻塞状态,一旦有客户端过来
		//创建子进程,子进程负责与客户端交互
		if ((connfd = accept(listenfd, NULL, NULL)) < 0)
		{
			perror("fail to accept");
			exit(-1);
		}
		if ((pid = fork()) < 0)
		{
			perror("fail to fork");
			exit(-1);
		}
		else if (pid == 0)
		{
			//子进程不需要监听,可以关闭
			close(listenfd);
			do_client(connfd);
		}
		//父进程不需要连接,可以关闭
		close(connfd);
	}

	return 0;
}

void do_client(int connfd)
{
	MSG buf;
	int len;
	int i = 0;
	//将从客户端接收的数据保存在buf中
	while (recv(connfd, &buf, sizeof(buf), 0) > 0)  
	{
		switch ( buf.type )
		{
		case 1 :
			len = strlen(buf.data);//计算长度
			printf("客户端过来的数据是:%s 长度为:%d\n",buf.data,len);
			sprintf(buf.data,"%d",len);//将长度保存在这返回个客户端
			send(connfd, &buf, sizeof(buf), 0);//将处理后的数据发送给客户端
			break;
		case 2 :
			len = strlen(buf.data);
			for(i = 0; i < len; i++)
			{
				if(buf.data[i] == 'i')
				{
					buf.type = 0;//表示有
					break;
				} 
			}
			if(buf.type == 0)
			{
				printf("客户端过来的数据是:%s 有i\n",buf.data);
				bzero(buf.data,256);
				//strcpy(buf.data,"有 i");
				sprintf(buf.data,"有 i",stdin);
			}else{
				printf("客户端过来的数据是:%s 没有i\n",buf.data);
				bzero(buf.data,256);
				sprintf(buf.data,"没有 i",stdin);
			}
			send(connfd, &buf, sizeof(buf), 0);
			break;
		}
	}
	printf("\nclient quit\n");
	exit(0);

	return;
}


客户端
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sqlite3.h>
#include <signal.h>
#include <time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

/**
	客户端
*/

/*
	定义一个结构体
*/
typedef struct 
{
	int type; //给服务端发送请求码
	char data[256];   // 接收服务器段的数据
} MSG;

int main()
{
	int connfd, listenfd;//定义连接文件描述符 与 监听描述符

	/*struct sockaddr_in则是internet环境下套接字的地址形式,是结构体
	一般情况下,需要把sockaddr_in结构强制转换成sockaddr结构再传入系统调用函数中。*/
	struct sockaddr_in myaddr;
	/**1、参数domain指明通信域,如PF_UNIX(unix域),PF_INET(IPv4),  
      PF_INET6(IPv6)等  
	   2、type指明通信类型,最常用的如SOCK_STREAM(面向连接可靠方式,  
      比如TCP)、SOCK_DGRAM(非面向连接的非可靠方式,比如UDP)等。
   	   3、参数protocol指定需要使用的协议
	*/
	if((listenfd = socket(PF_INET, SOCK_STREAM, 0)) < 0)
	{
		perror("fail to socket");
		exit(-1);
	}

	bzero(&myaddr,sizeof(myaddr));	//清空数据
	myaddr.sin_family = PF_INET;	//套接字的网络地址
	myaddr.sin_port = htons(atoi("8888"));//服务器端口号
	myaddr.sin_addr.s_addr = inet_addr("127.0.0.1");//服务器端ip地址
	//绑定端口号与ip地址   把sockaddr_in结构强制转换成sockaddr结构
	/* 客户程序发起连接请求 */ 
	 if(connect(listenfd,(struct sockaddr *)(&myaddr),sizeof(struct sockaddr))==-1) 
	 { 
	 	perror("connect");
	  	exit(1); 
	 } 

	 /* 连接成功了 */ 
    printf("------------ Client is running --------\n");
 	MSG msg;
	while(1)
	{
		printf("\n输入1计算长度,输入2查找字符串是否有i,输入3表示退出:\n");
		int type = 0;
		scanf("%d", &type);
		if(type == 3)
			break;
		msg.type = type;
		printf("输入内容:");
		//fgets(msg.data,256,stdin);
		scanf("%s", msg.data);
		msg.data[strlen(msg.data)] = '\0';
		send(listenfd, &msg, sizeof(MSG) ,0); //向服务器发送数据
		
		recv(listenfd, &msg, sizeof(MSG), 0);;//等待服务器的数据
		printf("------------ 结果为:%s --------\n", msg.data);
	}
		 /* 结束通讯 */ 
		close(listenfd); 
		exit(0);

	return 0;
}


最后贴上运行图:
服务器端:运行结果



客户端:运行结果

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: