Socket API编程模型
1. Socket API
1.1 Socket基础知识
socket通讯原理示意图
socket网络编程接口示意图(下左图示)以及LWIP中的socket的实现框图(下右图示)
IP地址转换、IP地址结构以及字节序转换的相关介绍可参考之前的网络编程基础
1.2 Socket API接口函数
为了兼容性,LWIP的socket也提供了标准的socket接口函数,在socket.h文件中可以看到下面的宏定义
//sockets.h
#define accept(s,addr,addrlen) lwip_accept(s,addr,addrlen)
/** @ingroup socket */
#define bind(s,name,namelen) lwip_bind(s,name,namelen)
/** @ingroup socket */
#define shutdown(s,how) lwip_shutdown(s,how)
/** @ingroup socket */
#define getpeername(s,name,namelen) lwip_getpeername(s,name,namelen)
/** @ingroup socket */
#define getsockname(s,name,namelen) lwip_getsockname(s,name,namelen)
/** @ingroup socket */
#define setsockopt(s,level,optname,opval,optlen) lwip_setsockopt(s,level,optname,opval,optlen)
/** @ingroup socket */
#define getsockopt(s,level,optname,opval,optlen) lwip_getsockopt(s,level,optname,opval,optlen)
/** @ingroup socket */
#define closesocket(s) lwip_close(s)
/** @ingroup socket */
#define connect(s,name,namelen) lwip_connect(s,name,namelen)
/** @ingroup socket */
#define listen(s,backlog) lwip_listen(s,backlog)
/** @ingroup socket */
#define socket(domain,type,protocol) lwip_socket(domain,type,protocol)
/** @ingroup socket */
#define select(maxfdp1,readset,writeset,exceptset,timeout) lwip_select(maxfdp1,readset,writeset,exceptset,timeout)
/** @ingroup socket */
#define ioctlsocket(s,cmd,argp) lwip_ioctl(s,cmd,argp)
/** @ingroup socket */
#define recv(s,mem,len,flags) lwip_recv(s,mem,len,flags)
/** @ingroup socket */
#define recvfrom(s,mem,len,flags,from,fromlen) lwip_recvfrom(s,mem,len,flags,from,fromlen)
/** @ingroup socket */
#define send(s,dataptr,size,flags) lwip_send(s,dataptr,size,flags)
/** @ingroup socket */
#define sendmsg(s,message,flags) lwip_sendmsg(s,message,flags)
/** @ingroup socket */
#define sendto(s,dataptr,size,flags,to,tolen) lwip_sendto(s,dataptr,size,flags,to,tolen)
//#if LWIP_POSIX_SOCKETS_IO_NAMES
/** @ingroup socket */
#define read(s,mem,len) lwip_read(s,mem,len)
/** @ingroup socket */
#define write(s,dataptr,len) lwip_write(s,dataptr,len)
/** @ingroup socket */
#define writev(s,iov,iovcnt) lwip_writev(s,iov,iovcnt)
/** @ingroup socket */
#define close(s) lwip_close(s)
/** @ingroup socket */
#define fcntl(s,cmd,val) lwip_fcntl(s,cmd,val)
/** @ingroup socket */
#define ioctl(s,cmd,argp) lwip_ioctl(s,cmd,argp)
常用的几种socket编程基本函数的详细介绍,可参考socket编程一文
2. TCP编程模型
TCP编程CS模型流程图如下图示
2.1 TCP Server端实例
要实现的功能为:将从PC客户端输入的小写字母转换为大写字母
-
参考带操作系统移植LWIP将LWIP移植到F4开发板中,并能够ping通开发板
-
在工程中创建socket_tcp_server.c和socket_tcp_server.h两个文件
/******socket_tcp_server.c******/
#include "socket_tcp_server.h"
#include "lwip/sockets.h"
#include "ctype.h"
char ReadBuff[BUFF_SIZE];
//TCP服务器任务
void vTcpServerTask(void){
int sfd, cfd, n, i;
struct sockaddr_in server_addr, client_addr;
socklen_t client_addr_len;
//创建socket
sfd = socket(AF_INET, SOCK_STREAM, 0);
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(SERVER_PORT);
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
//绑定socket
bind(sfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
//监听socket
listen(sfd, 5);
//等待客户端连接
client_addr_len = sizeof(client_addr);
cfd = accept(sfd, (struct sockaddr *)&client_addr, &client_addr_len);
printf("client is connect cfd = %d\r\n",cfd);
while(1){
//等待客户端发送数据
n = read(cfd, ReadBuff, BUFF_SIZE);
//进行大小写转换
for(i = 0; i < n; i++){
ReadBuff[i] = toupper(ReadBuff[i]);
}
//写回客户端
write(cfd, ReadBuff, n);
}
}
/******socket_tcp_server.h******/
#ifndef _SOCKET_TCP_SERVER_H
#define _SOCKET_TCP_SERVER_H
#define SERVER_IP "192.168.1.20" //客户端编程时需要用到该服务器地址
#define SERVER_PORT 6666
#define BUFF_SIZE 1024
void vTcpServerTask(void);
#endif
- 在freertos.c文件中的默认任务里面添加代码
void StartDefaultTask(void const * argument){
/* init code for LWIP */
MX_LWIP_Init();
/* USER CODE BEGIN StartDefaultTask */
printf("TCP server started!\r\n",cfd);
/* Infinite loop */
for(;;){
vTcpServerTask();
osDelay(100);
}
/* USER CODE END StartDefaultTask */
}
- 编译无误下载到开发板后,打开串口助手可以看到相关调试信息,使用网络调试工具创建一个PC客户端,连接相应IP和端口后,输入任意小写字母,Server将返回对应的大写字母
2.2 TCP Client端实例
要实现的功能为:将从PC服务端输入的小写字母转换为大写字母
-
参考带操作系统移植LWIP将LWIP移植到F4开发板中,并能够ping通开发板
-
在工程中创建socket_tcp_client.c和socket_tcp_client.h两个文件
/******socket_tcp_client.c******/
#include "socket_tcp_server.h"
#include "socket_tcp_client.h"
#include "lwip/sockets.h"
#include "ctype.h"
static char ReadBuff[BUFF_SIZE];
void vTcpClientTask(void){
int cfd, n, i;
struct sockaddr_in server_addr;
//创建socket
cfd = socket(AF_INET, SOCK_STREAM, 0);
//填充地址信息
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(SERVER_PORT);
server_addr.sin_addr.s_addr = inet_addr(SERVER_IP);//即PC端地址
//连接到服务器
connect(cfd, (struct sockaddr*)&server_addr, sizeof(server_addr));
printf("server is connect ok\r\n");
while(1){
//等待服务器发送数据
n = read(cfd, ReadBuff, BUFF_SIZE);
//进行大小写转换
for(i = 0; i < n; i++){
ReadBuff[i] = toupper(ReadBuff[i]);
}
//写回服务器
write(cfd, ReadBuff, n);
}
}
/******socket_tcp_client.h******/
#ifndef _SOCKET_TCP_CLIENT_H
#define _SOCKET_TCP_CLIENT_H
void vTcpClientTask(void);
#endif
- 在freertos.c文件中的默认任务里面添加代码
void StartDefaultTask(void const * argument){
/* init code for LWIP */
MX_LWIP_Init();
/* USER CODE BEGIN StartDefaultTask */
printf("TCP server started!\r\n",cfd);
/* Infinite loop */
for(;;){
vTcpClientTask();
osDelay(100);
}
/* USER CODE END StartDefaultTask */
}
- 编译无误下载到开发板后,打开串口助手可以看到相关调试信息,使用网络调试工具创建一个PC服务端,开始监听服务端IP和端口后,输入任意小写字母,Client端将返回对应的大写字母
3. UDP编程模型
UDP编程CS模型流程图如下图示
要实现的功能为:将从PC客户端输入的小写字母转换为大写字母
-
参考带操作系统移植LWIP将LWIP移植到F4开发板中,并能够ping通开发板
-
在工程中创建socket_udp_server.c和socket_udp_server.h两个文件
/******socket_udp_server.c******/
#include "socket_udp_server.h"
#include "lwip/sockets.h"
#include "ctype.h"
static char ReadBuff[BUFF_SIZE];
void vUdpServerTask(void){
int sfd, n, i;
struct sockaddr_in server_addr, client_addr;
socklen_t client_addr_len;
//创建数据包套接字(UDP)
sfd = socket(AF_INET, SOCK_DGRAM, 0);
//填充地址信息
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(SERVER_PORT);
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
//绑定socket
bind(sfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
client_addr_len = sizeof(client_addr);
while(1){
//等待客户端发送数据
n = recvfrom(sfd,ReadBuff,BUFF_SIZE,0,(struct sockaddr *)&client_addr, &client_addr_len);
ReadBuff[n] = '\0';
printf("recv data:%s\r\n",ReadBuff);
//进行大小写转换
for(i = 0; i < n; i++){
ReadBuff[i] = toupper(ReadBuff[i]);
}
//写回客户端
sendto(sfd,ReadBuff,n,0,(struct sockaddr *)&client_addr,client_addr_len);
}
}
/******socket_udp_client.h******/
#ifndef _SOCKET_UDP_SERVER_H
#define _SOCKET_UDP_SERVER_H
#define SERVER_PORT 6666
#define BUFF_SIZE 1024
void vUdpServerTask(void);
#endif
- 在freertos.c文件中的默认任务里面添加代码
void StartDefaultTask(void const * argument){
/* init code for LWIP */
MX_LWIP_Init();
/* USER CODE BEGIN StartDefaultTask */
printf("TCP server started!\r\n",cfd);
/* Infinite loop */
for(;;){
vUdpServerTask();
osDelay(100);
}
/* USER CODE END StartDefaultTask */
}
- 编译无误下载到开发板后,打开串口助手可以看到相关调试信息,使用网络调试工具创建一个PC客户端,连接相应IP和端口后,输入任意小写字母,Server将返回对应的大写字母