socket单连接服务器
socket单连接服务器
首先来了解一下,单连接socekt服务器用到的posix标准函数
int socket(int domain, int type, int protocol);
int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
int listen(int sockfd, int backlog);
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
int setsockopt(int sockfd, int level, int optname,const void *optval, socklen_t optlen);
int getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen);
使用以上函数时有下面两种方式判断是否执行成功,例如使用socket:
1、使用如下方式,需要注意‘=’的优先级比 < 低,因此需要加()
if((socket_fd = socket(domain,type,protocol)) < 0)
{
perror();
}
2、推荐此种使用方式,直观不易出错
socket_fd = socket(domain,type,protocol);
if(socket_fd < 0)
{
perror();
}
具体代码如下
#define ethernet_DATA_MAX_LEN 5000
#define ethernet_PORT 1002
static bool haveConnectFlag;
void socket_init(void);
void* ethernet_recv_thread_handle(void *arg);
int ethernet_msg_send(uint8_t *buf);
int main()
{
socket_init();
}
void socket_init(void)
{
pthread_t ethernet_recv_thread;
/*初始化socket,如果不成功间隔1s一直初始化*/
while(1)
{
sleep(1);
/*创建socket套接字*/
socket_ethernet_fd = socket(AF_INET, SOCK_STREAM, 0);
if(socket_ethernet_fd < 0)
{
printf("socket error: %s(errno: %d)", strerror(errno), errno);
close(socket_ethernet_fd);
continue;
}
memset(&socketaddr, 0, sizeof(socketaddr));
socketaddr.sin_family = AF_INET;
socketaddr.sin_port = htons(ethernet_PORT);
socketaddr.sin_addr.s_addr = htonl(INADDR_ANY);
getsockopt(socket_ethernet_fd, IPPROTO_TCP, TCP_MAXSEG, &mss, (socklen_t *)&mssLen);
printf("server initial max MSS is %d.\r\n", mss);
/*设置socket_ethernet_fd套接字的选项值,使下一次使用ip和端口号不需要等待*/
ret = setsockopt(socket_ethernet_fd, SOL_SOCKET, SO_REUSEADDR, &ReUseOn, sizeof(ReUseOn));
if(ret < 0)
{
printf("setsockopt error: %s(errno: %d)", strerror(errno), errno);
close(socket_ethernet_fd);
continue;
}
/*绑定TCP协议族、IP和端口号*/
ret = bind(socket_ethernet_fd, (struct sockaddr*)&socketaddr, sizeof(socketaddr));
if(ret < 0)
{
printf("bind error: %s(errno: %d)", strerror(errno), errno);
close(socket_ethernet_fd);
continue;
}
/*监听socket_ethernet_fd套接字*/
ret = listen(socket_ethernet_fd, 10);
if(ret < 0)
{
printf("listen error: %s(errno: %d)", strerror(errno), errno);
close(socket_ethernet_fd);
continue;
}
else
{
break;
}
}
/*创建接收线程*/
pthread_create(ðernet_recv_thread, NULL, ethernet_recv_thread_handle, NULL);
}
void ethernet_recv_thread_handle(void *arg)
{
uint8_t buf[ethernet_DATA_MAX_LEN] = {0};
ssize_t recv_len;
int mss = 0, mssLen = sizeof(mss);
int keepalive = 1; //enable keepalive
int keepidle = 3; //idle time,will send explore data after this time
int keepinterval = 1; //send interval
int keepcount = 5; //send times
int ret = -1;
/*最外层while用于处理连接*/
while(1)
{
haveConnectFlag = false;
printf("waiting ethernet socket accept");
ethernet_cnnt_fd = accept(socket_ethernet_fd, (struct sockaddr*)NULL, NULL);
if(ethernet_cnnt_fd < 0)
{
printf("accept socket error: %s(errno: %d)",strerror(errno),errno);
continue;
}
haveConnectFlag = true;
getsockopt(socket_ethernet_fd, IPPROTO_TCP, TCP_MAXSEG, &mss, (socklen_t *)&mssLen);
printf("client max MSS is %d.\r\n", mss);
/*设置TCP心跳选项值*/
ret = setsockopt(ethernet_cnnt_fd, SOL_SOCKET, SO_KEEPALIVE, &keepalive, sizeof(keepalive));
if(ret < 0)
{
printf("SO_KEEPALIVE set error:%s(errno: %d)", strerror(errno), errno);
}
ret = setsockopt(ethernet_cnnt_fd, SOL_TCP, TCP_KEEPIDLE, &keepidle, sizeof(keepidle));
if(ret < 0)
{
printf("TCP_KEEPIDLE set error:%s(errno: %d)", strerror(errno), errno);
}
ret = setsockopt(ethernet_cnnt_fd, SOL_TCP, TCP_KEEPINTVL, &keepinterval, sizeof(keepinterval));
if(ret < 0)
{
printf("TCP_KEEPINTVL set error:%s(errno: %d)", strerror(errno), errno);
}
ret = setsockopt(ethernet_cnnt_fd, SOL_TCP, TCP_KEEPCNT, &keepcount, sizeof(keepcount));
if(ret < 0)
{
printf("TCP_KEEPCNT set error:%s(errno: %d)", strerror(errno), errno);
}
/*此while用于处理连接中,接收数据*/
while(1)
{
ethernet_recv_time_pre = time(NULL);
printf("waiting ethernet socket recv");
recv_len = recv(ethernet_cnnt_fd, buf, sizeof(buf),0);
if(recv_len > 0)
{
printf("recv data:%s\n",buf);
}
else if(recv_len == 0)
{
ethernet_datatype = 0;
printf("close ethernet_cnnt_fd");
close(ethernet_cnnt_fd);
break;
}
else//error
{
ethernet_datatype = 0;
printf("ethernet recv error:%s(errno: %d)", strerror(errno), errno);
close(ethernet_cnnt_fd);
break;
}
}
}
}
int ethernet_msg_send(uint8_t *buf)
{
int ret = -1;
/*在有连接情况下,发送数据给客户端*/
if(true == haveConnectFlag)
{
ret = send(ethernet_cnnt_fd, buf, len, 0);
printf("ethernet send msg! len = %d\n",len);
}
else
{
printf("no ethernet connect,can`t send msg!");
}
return ret;
}
注意:
1、socket是基于TCP流传输的,在实际传输数据过程中会出现粘包或者分段等情况,需要根据应用层数据协议来处理粘包或者分段;
2、查看指定端口号在当前系统中使用情况:netstat -an | grep 端口号;
3、以上代码均未写头文件,读者可自行在man手册中找到函数原型和头文件,读者也可进一步了解函数手册;

浙公网安备 33010602011771号