Server_socket实验用到的API大部分在前面已经进行讲解(只是对NETCONN接口编辑方式进行二次封装),本节只介绍一个比较关键的API:setsockopt(s,level,optname,opval,optlen)。
从名称中就可以看出函数功能用于设置套接字的一些选项,我们关注一下参数:
(1)level有多个常用的选项
SOL_SOCKET:表示在Socket层
IPPROTO_TCP:表示在TCP层
IPPROTO_IP:表示在IP层
(2)optname 表示该层的具体选项名称
level为SOL_SOCKET时,有以下选项:SO_REUSEADDR(允许重用本地地址和端口)、
SO_SNDTIMEO(设置发送数据超时时间)、SO_SNDTIMEO(设置接收数据超时时间)、SO_RCVBUF(设置发送数据缓冲区大小)等。
level为IPPROTO_TCP时,有以下选项:TCP_NODELAY(不使用Nagle算法)、TCP_KEEPALIVE(设置TCP保活时间)等。
level为IPPROTO_IP选项,有以下选项:IP_TTL(设置生存时间)、IP_TOS(设置服务类型)等。
实现Server_socket函数:static void server_socket(void* thread_param)
{
int sock = -1, connected;
char* recv_data;
struct sockaddr_in server_addr, client_addr;
socklen_t sin_size;
int recv_data_len;
printf("The local port number is%dnn", LOCAL_PORT);
recv_data = (char*)pvPortMalloc(RECV_DATA);
if (recv_data == NULL) {
printf("No memoryn");
goto __exit;
}
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
printf("Socket errorn");
goto __exit;
}
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(LOCAL_PORT);
memset(&(server_addr.sin_zero), 0, sizeof(server_addr.sin_zero));
if (bind(sock, (struct sockaddr*)&server_addr, sizeof(struct sockaddr)) == -1) {
printf("Unable to bindn");
goto __exit;
}
if (listen(sock, 5) == -1) { // (1)
printf("Listen errorn");
goto __exit;
}
while(1) {
sin_size = sizeof(struct sockaddr_in);
connected = accept(sock, (struct sockaddr*)&client_addr, &sin_size); // (2)
printf("new client connected from (%s, %d)n",
inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
{
int flag = 1;
setsockopt(connected,
IPPROTO_TCP, /* set option at TCP level */
TCP_NODELAY, /* name of option */
(void*) &flag, /* the cast is historical cruft */
sizeof(int)); /* length of option value */ // (3)
}
while(1) {
recv_data_len = recv(connected, recv_data, RECV_DATA, 0); // (4)
if (recv_data_len <= 0)
break;
printf("recv %d len datan", recv_data_len);
write(connected, recv_data, recv_data_len); // (5)
}
if (connected >= 0)
closesocket(connected); // (6)
connected = -1;
}
__exit:
if (sock >= 0) closesocket(sock);
if (recv_data) free(recv_data);
}
1)进入监听状态
2)阻塞应用线程直至与远端主机建立TCP连接,建立成功后远程主机的信息将保持在连接句柄中(connected)
3)对套接字connected进行设置:在TCP层,不使用Nagle算法
4)处理客户端的连接请求,接收远程主机信息
5)将接收的数据进行转发
6)主动关闭客户端的连接
到这里已经完成了Server_socket函数的创建,看一下PC的IP地址,设备需要处于同一网段方便测试。打开命令行窗口输入:ipconfig
PC的地址为:192.168.105.34,在sys_arch.h文件中对DEST_IP_ADDR0 、DEST_IP_ADDR1、DEST_IP_ADDR2、DEST_IP_ADDR3进行修改,DEST_PORT 随意修改。#define LOCAL_PORT 2021
#define IP_ADDR0 192
#define IP_ADDR1 168
#define IP_ADDR2 105
#define IP_ADDR3 26
将程序下载入开发板中,使用NetAssist进行如下设置:
1)协议设置,此时设备为Server,则PC为Client
2)设置远程主机地址(即设备地址)
3)端口号
点击连接,若提示连接失败,则Ping一下开发板地址,可以正常Ping通则检查端口号;如果无法Ping通则需要对工程进行检查。