0. 相关头文件
#
include
<sys
/socket.h
>
# include <netinet /in.h >
# include <arpa /inet.h >
# include <netinet /in.h >
# include <arpa /inet.h >
#
include
<sys
/epoll.h
>
# include <fcntl.h >
# include <fcntl.h >
#
include
<unistd.h
>
#include <sys/time.h>
#
include
<stdio.h
>
# include <stdlib.h >
# include <stdlib.h >
#
include
<memory.h
>
#
include
<assert.h
>
#
include
<pthread.h
>
#
include
<errno.h
>
1.socket初始化
s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(s == -1) return -1;
s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(s == -1) return -1;
s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(s == -1) return -1;
if(s == -1) return -1;
struct sockaddr_in stAddr;
memset(&stAddr, 0, sizeof(stAddr));
stAddr.sin_family = AF_INET;
stAddr.sin_addr.s_addr = inet_addr(pszIp);
stAddr.sin_port = ntohs(ushPort);
if(bind(s, (struct sockaddr*)&stAddr, sizeof(stAddr)) == -1)
{
return -2;
}
2.非阻塞
//set non-blocking
//set non-blocking
void setNonBlock(
int sock_fd )
{
int opts;
opts = fcntl( sock_fd, F_GETFL );
if( opts < 0 )
{
printf( "err:fcntl F_GETFL");
exit( 1 );
}
opts = opts | O_NONBLOCK ;
if( fcntl( sock_fd, F_SETFL, opts ) < 0 )
{
printf( "err:fcntl F_SETFL");
exit( 1 );
}
}
{
int opts;
opts = fcntl( sock_fd, F_GETFL );
if( opts < 0 )
{
printf( "err:fcntl F_GETFL");
exit( 1 );
}
opts = opts | O_NONBLOCK ;
if( fcntl( sock_fd, F_SETFL, opts ) < 0 )
{
printf( "err:fcntl F_SETFL");
exit( 1 );
}
}
3.设置端口复用
使多个Socket对象绑定在同一个端口上
//set socket port reuse
if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &flags, sizeof(flags)) == - 1)
{
return - 1;
}
if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &flags, sizeof(flags)) == - 1)
{
return - 1;
}
4.自定义各类缓冲大小
//reset recv buf len
if(setsockopt(s, SOL_SOCKET, SO_RCVBUF, ( char *) &iRcvBufLen, sizeof(iRcvBufLen)) == - 1)
{
return - 1;
}
//reset send buf len
if(setsockopt(s, SOL_SOCKET, SO_SNDBUF, ( char *) &iSendBufLen, sizeof(iSendBufLen)) == - 1)
{
return - 1;
}
if(setsockopt(s, SOL_SOCKET, SO_SNDBUF, ( char *) &iSendBufLen, sizeof(iSendBufLen)) == - 1)
{
return - 1;
}
5.设置tcp nodelay( 关闭 Nagle算法 )
1) 在实时性要求较高时要关闭
2) Nagle算法用来减少少报文数目
int flag
=
1;
int result = setsockopt(sock, /* socket affected */
IPPROTO_TCP, /* set option at TCP level */
TCP_NODELAY, /* name of option */
( char *) &flag, /* the cast is historical
cruft */
sizeof( int)); /* length of option value */
int result = setsockopt(sock, /* socket affected */
IPPROTO_TCP, /* set option at TCP level */
TCP_NODELAY, /* name of option */
( char *) &flag, /* the cast is historical
cruft */
sizeof( int)); /* length of option value */
6.设置SO_LINGER
将linger参数设为一个正整数n时(n的值最大是65,535),在调用close方法后,将最多被阻塞n秒。在这n秒内,系统将尽量将未送出的数据包发送出去;如果超过了n秒,如果还有未发送的数据包,这些数据包将全部被丢弃;而close方法会立即返回。如果将linger设为0,和关闭SO_LINGER选项的作用是一样的。
SO_LINGER选项用来改变此缺省设置。使用如下结构:
struct linger {
int l_onoff; /* 0 = off, nozero = on */
int l_linger; /* linger time */
};
struct linger so_linger;
so_linger.l_onoff = TRUE;
so_linger.l_linger = 30;
int result = setsockopt(s,
SOL_SOCKET,
SO_LINGER,
&so_linger,
sizeof so_linger);
int l_onoff; /* 0 = off, nozero = on */
int l_linger; /* linger time */
};
struct linger so_linger;
so_linger.l_onoff = TRUE;
so_linger.l_linger = 30;
int result = setsockopt(s,
SOL_SOCKET,
SO_LINGER,
&so_linger,
sizeof so_linger);
7.设置SO_KEEPALIVE
客户端Socket每隔段的时间(大约两个小时)就会利用空闲的连接向服务器发送一个数据包。这个数据包并没有其它的作用,只是为了检测一下服务器是否仍处于活动状态
keepAlive
=
1;
setsockopt(listenfd, SOL_SOCKET, SO_KEEPALIVE, ( void *) &keepAlive, sizeof(keepAlive));
setsockopt(listenfd, SOL_SOCKET, SO_KEEPALIVE, ( void *) &keepAlive, sizeof(keepAlive));
8.服务器初始化
listen_fd
= socket( AF_INET, SOCK_STREAM,
0);
memset( &svrAddr, 0 , sizeof( sockaddr_in ) );
inet_aton( "127.0.0.1", &svrAddr.sin_addr );
svrAddr.sin_family = AF_INET;
svrAddr.sin_port = htons( 12345 );
int ret;
ret = bind( listen_fd, (sockaddr *) &svrAddr, sizeof( sockaddr_in ) );
if( ret != 0 )
{
perror( "bind fail" );
exit( - 3);
}
listen( listen_fd, 20 );
9. Accept
//一定要初始化长度,否则很容易accept出错
clnLen
=
sizeof( sockaddr_in );
memset( &clnAddr, 0 , sizeof( sockaddr_in ) );
conn_fd = accept( listen_fd, (sockaddr *) &clnAddr, &clnLen );
if( conn_fd < 0 )
{
perror( "conn_fd < 0");
break;
}