物联网网关开发技术学习笔记——嵌入式linux网络编程2——socket TCP

TCP编程流程图

在这里插入图片描述

TCP服务端编程步骤

(1) 建立套接字stock()

在这里插入图片描述

服务端:

int listen_fd;
listen_fd=socket(AF_INET,SOCK_STREAM,0);
	if(listen_fd<0)
	{
		perror("Failed to create socket:");
		return -1;
	}

客服端:

int client_fd;
client_fd=socket(AF_INET,SOCK_STREAM,0);	//网络端应用程序

(2) 对创建的套接字指定ip地址和端口号(bind)

在这里插入图片描述

① 服务端:提供服务的一端,它始终等待别人的服务请求,只有“别人主动找它联系,而永远不会主动找别人联系”。为了让别人能够找到它,它必须公开其socket属性:ip地址——端口号
因此需要通过bind()函数显式指定其ip地址和端口号
② 客户端:请求服务的一端,主动联系别人的一方,因为它并不需别人来找它,所以无须公开其socket属性
因此不需要通过bind()函数显式指定其ip地址和端口号,该soket的其ip地址和端口在通信时由系统自动分配

服务端:

int ret;
int sock_size=sizeof(struct sockaddr_in);
struct sockaddr_in server_addr;
bzero(&server_addr,sock_size);
server_addr.sin_family=AF_INET;
server_addr.sin_port=htons(8000);
server_addr.sin_addr.s_addr=INADDR_ANY;
setsockopt(listen_fd,SOL_SOCKET,SO_REUSEADDR,&i,sizeof(int));
ret=bind(listen_fd,(struct sockaddr*)&server_addr,sock_size);
if(ret==0)
{
	printf("Bind Successfully!\n");
}

注意:INADDR_ANY表示可以接受本机所有网卡所有ip地址的数据;如果把INADDR_ANY换成inet_addr(“192.168.0.103”),则表示只会接收本机ip地址为192.168.0.103上的数据

(3) 对套接字进行侦听(listen)

在这里插入图片描述

通常会建立一个连接队列,进行通信的只能一个客户端
让sockfd处处于监听外来请求的状态,可以把请求加入到请求队列里面等候处理(accept()函数)!
在这里插入图片描述

服务端:

ret=listen(listen_fd,MAXCONN);
	if(ret==0)
	{
		printf("Listen Successfully!\n");
	}

(4) 套接字等待连接(accept)

在这里插入图片描述

它的调用将意味着服务端开始处理外来请求,如果没有外来请求(也就是没有listen到请求进来)默认情况下则阻塞

服务端:

int comm_fd;
while((comm_fd=accept(listen_fd,(struct sockaddr*)&client_addr,&sock_size))>=0)
	{
		信息交互
	}

TCP客服端编程步骤

(1) 向服务端发起连接请求connect()

在这里插入图片描述

【前提是服务端已经进入等待连接accept】 客户端套接字sockfd向服务器端serv_addr发起连接请求

客户端:

server_addr.sin_family=AF_INET;
server_addr.sin_port=htons(8000);
server_addr.sin_addr.s_addr=inet_addr(argv[1]);
ret=connect(client_fd,(struct sockaddr*)&server_addr,sock_size);
	if(ret<0)
	{
		perror("Failed to connect:");
		return -1;
	}
	printf("Connect successfully!\n");
while(1)
	{
		信息交互
	}

连接请求成功后通过send()和recv()通信

(1) 发送信息send()

在这里插入图片描述

当send返回时,并不是表示数据已经发送到了对方,而仅仅表示数据已经到了协议栈的缓冲区中。

(2) 接收信息recv()

在这里插入图片描述

默认情况下,当没有可接收的数据时则阻塞,参数len表示最多接收多少个字节数, 成功的接受的字节数完全可以小于len!!

客服端:

int ret;
int count;
struct sockaddr_in server_addr;
char buf[512];
char recv_buf[512];
while((comm_fd=accept(listen_fd,(struct sockaddr*)&client_addr,&sock_size))>=0)
	{
		char ipaddr[16];
		inet_ntop(AF_INET,&client_addr.sin_addr.s_addr,ipaddr,16);
		printf("A connection come on:%s\n",ipaddr);
		while(1)
		{
			char buff[512];
			int count;
			count=read(comm_fd,buff,511);
			if(count>0)
			{
				buff[count]=0;
				printf("A String from %s:%s\n",ipaddr,buff);
				if(strncmp(buff,"quit",4)==0)
				{
					printf("A talking is over!\n");
					break;
				}
				write(comm_fd,buff,count);
			}
			else
			{
				printf("A talking is over!\n");
				break;					
			}
		}
	}

服务端:

while(1)
		{
			char buff[512];
			int count;
			count=read(comm_fd,buff,511);
			if(count>0)
			{
				buff[count]=0;
				printf("A String from %s:%s\n",ipaddr,buff);
				if(strncmp(buff,"quit",4)==0)
				{
					printf("A talking is over!\n");
					break;
				}
				write(comm_fd,buff,count);
			}
			else
			{
				printf("A talking is over!\n");
				break;					
			}
		}
	}

实验要求:

服务端:
接收客户端所传输的文本信息同时显示客户端的IP地址并把文本信息回传给客户端,当收到quit时退出本次服务
客户端:
把从键盘输入的字符串发送给客户端,同时等待服务端的回传信息

客服端代码:

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h>	//socket函数所需的头函数
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <strings.h>
int main(int argc,char **argv)
{
	int client_fd;
	int ret;
	int count;
	struct sockaddr_in server_addr;
	char buf[512];
	char recv_buf[512];
	int sock_size=sizeof(struct sockaddr_in);
	if(argc<2)
	{
		printf("Usage:./client serverip\n");
		return 0;
	}
	bzero(&server_addr,sock_size);
	client_fd=socket(AF_INET,SOCK_STREAM,0);	//网络端应用程序
	server_addr.sin_family=AF_INET;
	server_addr.sin_port=htons(8000);
	server_addr.sin_addr.s_addr=inet_addr(argv[1]);
	ret=connect(client_fd,(struct sockaddr*)&server_addr,sock_size);
	if(ret<0)
	{
		perror("Failed to connect:");
		return -1;
	}
	printf("Connect successfully!\n");
	while(1)
	{
		fgets(buf,512,stdin);
		ret=write(client_fd,buf,strlen(buf));
		if(ret<=0)
			break;
		if(strncmp(buf,"quit",4)==0)
			break;	
		count=read(client_fd,recv_buf,511);
		if(count>0)
		{
			recv_buf[count]=0;
			printf("Echo:%s\n",recv_buf);
		}	
		else
		{
			break;
		}
	}
	close(client_fd);
	return 0;
	
}

服务端代码:

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <strings.h>
#define MAXCONN 8
int main()
{
	int listen_fd,comm_fd;
	int ret;
	int i=1;
	struct sockaddr_in server_addr,client_addr;
	int sock_size=sizeof(struct sockaddr_in);
	listen_fd=socket(AF_INET,SOCK_STREAM,0);
	if(listen_fd<0)
	{
		perror("Failed to create socket:");
		return -1;
	}
	bzero(&server_addr,sock_size);
	server_addr.sin_family=AF_INET;
	server_addr.sin_port=htons(8000);
	server_addr.sin_addr.s_addr=INADDR_ANY;
	setsockopt(listen_fd,SOL_SOCKET,SO_REUSEADDR,&i,sizeof(int));
	ret=bind(listen_fd,(struct sockaddr*)&server_addr,sock_size);
	if(ret==0)
	{
		printf("Bind Successfully!\n");
	}
	ret=listen(listen_fd,MAXCONN);
	if(ret==0)
	{
		printf("Listen Successfully!\n");
	}
	while((comm_fd=accept(listen_fd,(struct sockaddr*)&client_addr,&sock_size))>=0)
	{
		char ipaddr[16];
		inet_ntop(AF_INET,&client_addr.sin_addr.s_addr,ipaddr,16);
		printf("A connection come on:%s\n",ipaddr);
		while(1)
		{
			char buff[512];
			int count;
			count=read(comm_fd,buff,511);
			if(count>0)
			{
				buff[count]=0;
				printf("A String from %s:%s\n",ipaddr,buff);
				if(strncmp(buff,"quit",4)==0)
				{
					printf("A talking is over!\n");
					break;
				}
				write(comm_fd,buff,count);
			}
			else
			{
				printf("A talking is over!\n");
				break;					
			}
		}
	}
	close(listen_fd);
	return 0;
	
}

编程步骤:
(1) 将服务端代码和客服端代码在Linux下执行
gcc -o sever sever.c
gcc -o client client.c
(2) 打开网络调试助手,设置成tcp客服端,端口号0
在这里插入图片描述

(3) 打开两个终端窗口(这两步不能先后调换) 先执行服务端;后执行客服端,连接本机ip
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值