基于UDP/TCP的 c/s 通信模型

基于UDP c/s通信模型

  • 客户端(socket;sendto ...)  
  • 服务器端  ---把自己的地址公布出去 (socket;bind //绑定; recvfrom ...)

1.recvfrom函数:

 ssize_t recvfrom( int sockfd,    //socket的fd
                               void *buf,    //保存数据的一块空间的地址 
                             size_t len,    //这块空间的大小 
                               int flags,    // 0  默认的接收方式 --- 阻塞方式 
   struct sockaddr *src_addr,    //用来保存发送方的地址信息 
            socklen_t *addrlen     //表示发送方实际的地址信息大小  ); 

返回值:成功:返回接收到的字节数; 失败:-1。 

  

struct sockaddr_in srcaddr;
socklen_t addrlen = sizeof(srcaddr);

char buf[1024];
   
while(1)
{
    recvfrom(fd,buf,sizeof(buf),0,(struct sockaddr *)&srcaddr,&addrlen);
        
    printf("IP = %s\n",inet_ntoa(srcaddr.sin_addr));
    printf("post = %d\n",ntohs(srcaddr.sin_port));
    printf("buf = %s\n",buf);
}

2.bind函数:

 int bind(int sockfd,  const struct sockaddr *addr, socklen_t addrlen);

        (1)功能:如果该函数在服务器端调用,则表示将参数1相关的文件描述符文件与参数2 指定的接口地址关联,用于从该接口接受数据。如果该函数在客户端调用,则表示要将数据从参数1所在的描述符中取出并从参数2所在的接口设备上发送出去。

        注意:如果是客户端,则该函数可以省略,由默认接口发送数据。
        (2)参数:sockfd之前通过socket函数创建的文件描述符,套接字id; my_addr 是物理接口的结构体指针。表示该接口的信息。  

struct sockaddr      通用地址结构 --- ip + 端口 
{
    u_short sa_family;  地址族
    char sa_data[14];   地址信息
};


转换成网络地址结构如下:
struct sockaddr_in    ///网络地址结构
{
    u_short           sin_family; //地址族
    u_short           sin_port;   //地址端口
    struct in_addr  sin_addr;   //地址IP  //"192.168.1.123"
    char               sin_zero[8]; //占位
};
 

in_addr_t  === unsigned int 
struct in_addr
{
    in_addr_t s_addr;
}
          

练习:

           任务1 从键盘获得数据发给服务器  --fgets
           任务2 从服务器不断获取数据打印  --recvfrom 

1.客户端:
int c_fd = 0;
void child_handler(int signo)
{

	close(c_fd);
    printf("child--exit--\n");
	exit(0);

}

void father_handler(int signo)
{

	close(c_fd);
    printf("father--exit--\n");
	exit(0);
}

int main(int argc, const char *argv[])
{
	//1.socket 创建通信的一端 
	int fd = socket(AF_INET,SOCK_DGRAM,0);

	if (fd < 0)
	{
		perror("socket fail");
		return -1;
	}
	
	printf("fd = %d\n",fd);

	struct sockaddr_in seraddr;
	seraddr.sin_family = AF_INET;
	seraddr.sin_port = htons(50000);
	seraddr.sin_addr.s_addr = inet_addr("192.168.1.135");

	char buf[1024] = {0};

	//区分任务 
	pid_t pid = fork();

	if (pid < 0)
	{
		perror("fork fail");
		return -1;
	}

	if (pid > 0)
	{
		signal(SIGCHLD,father_handler);
		c_fd = fd;
		while (1)
		{
			printf(">");
			fgets(buf,sizeof(buf),stdin);
			int ret = sendto(fd,buf,strlen(buf)+1,0,(const struct sockaddr *)&seraddr,sizeof(seraddr));
			printf("ret = %d\n",ret);

			if (strncmp(buf,"quit",4) == 0)
			{
				kill(pid,SIGUSR1);
				wait(NULL);
				close(fd);
				exit(0);
			}
		}
		
	}else if (pid == 0) 
	{
		c_fd = fd;
		signal(SIGUSR1,child_handler);
		while (1)
		{
			recvfrom(fd,buf,sizeof(buf),0,NULL,NULL);
			printf("buf = %s\n",buf);

			if (strncmp(buf,"quit",4) == 0)
			{
				close(fd);
				exit(0);
			}
		}
	}
		
	//close(fd); 
	return 0;
}
2.服务器端:       
int c_fd = 0;
void child_handler(int signo)
{

	close(c_fd);
    printf("child--exit--\n");
	exit(0);

}

void father_handler(int signo)
{

	close(c_fd);
    printf("father--exit--\n");
	exit(0);
}

int main(int argc, const char *argv[])
{

	//1.socket 创建通信的一端 
	int fd = socket(AF_INET,SOCK_DGRAM,0);

	if (fd < 0)
	{
		perror("socket fail");
		return -1;
	}	

	struct sockaddr_in seraddr;
	seraddr.sin_family = AF_INET;
	seraddr.sin_port = htons(50000);
	seraddr.sin_addr.s_addr = inet_addr("192.168.1.135");
	//2.bind
	if (bind(fd,(struct sockaddr *)&seraddr,sizeof(seraddr)) < 0)
	{
		perror("bind fail");
		return -1;
	}

	struct sockaddr_in srcaddr;
	socklen_t addrlen = sizeof(srcaddr);
	char buf[1024];
	//3.接收数据
	recvfrom(fd,buf,sizeof(buf),0,(struct sockaddr*)&srcaddr,&addrlen);
	printf("--------------------\n");
	printf("IP   = %s\n",inet_ntoa(srcaddr.sin_addr));
	printf("post = %d\n",ntohs(srcaddr.sin_port));
	printf("buf = %s\n",buf);
	printf("--------------------\n");

	pid_t pid = fork();

	if (pid < 0)
	{
		perror("fork fail");
		return -1;
	}

	if (pid > 0)
	{
		signal(SIGCHLD,father_handler);
        c_fd = fd;
		while (1)
		{
			//3.接收数据
			recvfrom(fd,buf,sizeof(buf),0,(struct sockaddr*)&srcaddr,&addrlen);
			printf("--------------------\n");
			printf("IP   = %s\n",inet_ntoa(srcaddr.sin_addr));
			printf("post = %d\n",ntohs(srcaddr.sin_port));
			printf("buf = %s\n",buf);
			printf("--------------------\n");
			
			if (strncmp(buf,"quit",4) == 0)
			{
				kill(pid,SIGUSR1);
				wait(NULL);
				close(fd);
				exit(0);
			}
		}

	}else if (pid == 0)
	{
		signal(SIGUSR1,child_handler);
		while (1)
		{
			printf(">");
			fgets(buf,sizeof(buf),stdin);
			sendto(fd,buf,strlen(buf) + 1, 0, (const struct sockaddr*)&srcaddr,sizeof(srcaddr));
			if (strncmp(buf,"quit",4) == 0)
			{
				close(fd);
				exit(0);
			}
		}
	}	
	
	return 0;
}

基于TCP c/s通信模型

tcp 客户端:

(1)建立连接:

  • socket //买了一部手机;
  • bind //可选   //插上sim卡;
  • connect    //拨打电话 ....

(2)通信过程:(read;write;close) 

connect函数:

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

        (1)功能:该函数固定有客户端使用,表示从当前主机向目标主机发起链接请求。
        (2)参数:sockfd:本地socket创建的套接子id;addr:程目标主机的地址信息;

                        addrlen: 参数2的长度。

        (3)返回值:成功 0;失败 -1;

int main(int argc, const char *argv[])
{
	int fd = socket(AF_INET,SOCK_STREAM,0);

	if (fd < 0)
		handle_error("socket fail");	


	struct sockaddr_in seraddr;
	seraddr.sin_family = AF_INET;
	seraddr.sin_port = htons(50000);
	seraddr.sin_addr.s_addr = inet_addr("192.168.1.135");

	if (connect(fd,(const struct sockaddr*)&seraddr,sizeof(seraddr)) < 0)
		handle_error("connect fail");

	
	return 0;
}

tcp服务器:

(1)建立连接 

  • socket  //买了一部手机 
  • bind    //插上sim卡 
  • listen  //监听 客户端的连接请求 
  • accept  //接听 ---这一步完成之后 连接就建立好了,之后就可以收发数据  

(2)通信过程 (read;write;close) 
     

listen函数:

 int listen(int sockfd, int backlog);

accept函数:

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

int main(int argc, const char *argv[])
{
	int listen_fd = socket(AF_INET,SOCK_STREAM,0);

	if (listen_fd < 0)
		handle_error("socket fail");	


	struct sockaddr_in seraddr;
	seraddr.sin_family = AF_INET;
	seraddr.sin_port = htons(50000);
	seraddr.sin_addr.s_addr = inet_addr("192.168.1.135");

	if (bind(listen_fd,(const struct sockaddr*)&seraddr,sizeof(seraddr)) < 0)
		handle_error("bind fail");


	if (listen(listen_fd,5) < 0)
		handle_error("listen fail");


	int connfd = accept(listen_fd,NULL,NULL);

	if (connfd < 0)
		handle_error("accept fail");

	printf("connfd = %d\n",connfd);

	return 0;
}

struct sockaddr *addr //通用地址结构类型,并没有实际去用,实际用到都是具体地址结构类型
           
           struct sockaddr_in {
               sa_family_t    sin_family; /* address family: AF_INET */
               in_port_t      sin_port;   /* port in network byte order */
               struct in_addr sin_addr;   /* internet address */
           };

           /* Internet address. */
           struct in_addr {
               uint32_t       s_addr;     /* address in network byte order */
           };
     

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值