判断主机字节序的程序:
int main(int argc, char **argv){
union{
short s;
char c[sizeof(short)];
}un;
un.s = 0×0102;
if(sizeof(short) == 2){
if(un.c[0]==1 && un.c[1]==2)
printf("BigEndian");
else if(un.c[0]==2 && un.c[1]==1)
printf("LittleEndian");
else
printf("unknown");
}else{
printf("sizeof(short): %d", sizof(short));
exit(0);
}
}
字节序转换的函数 ntohs/htons: 网络到主机用ntohs,主机到网络htons。
ILP\LP\LLP:
Linux用LP64
Windows LLP64
对齐系数:每个特定平台的编译器都有自己的对齐系数。可以通过预编译命令#progma pack(n),n=1,2,4,8,16来改变这一系数。
packed格式压缩结构体:
struct{
u16 id;
u64 lun;
u16 reserved1;
u32 reserved2;
}__attribute__((packed))
struct sockaddr_in{
unit8_t sin_len;
sa_family_t sin_family;
in_port_t sin_port;
struct in_addr sin_addr;
char sin_zero[8];
}
struct in_addr{
in_addr_t s_addr;
}
地址转换函数:
int inet_aton(char*, struct in_addr *);//将ascii码的IP地址转换为network网络字节序32位的IPV4bit值,1成功0失败
char *inet_ntoa(struct in_addr);//将network网络字节序转换为ascii码的点分十进制的字符串(xx.xx.xx.xx)
int inet_pton(int 地址族(4或6), const char * ,void *);//将protocol协议字符串转换为IPV4/6bit值
int *inet_ntop(int 地址族(4或6), const void* 地址结构体, char* 字符串, size_t length);//将network网络字节序转换为点分十进制的字符串
Epoll
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define MAXLINE 4096
#define LISTENQ 20
#define SERV_PORT 6666
int main(int argc, char *argv[])
{
int i, maxi, listenfd, connfd, sockfd, epfd, nfds;
ssize_t n;
char BUF[MAXLINE];
socklen_t clilen;
clilen=sizeof(struct sockaddr);
//ev用于注册事件,数组用于回传要处理的事件
struct epoll_event ev, events[20];
//生成用于处理accept的epoll专用的文件描述符
epfd = epoll_create(256);
struct sockaddr_in cliaddr, servaddr;
listenfd = socket(AF_INET, SOCK_STREAM, 0);
//setnonblocking(listenfd);
//设置与要处理的事件相关的文件描述符
ev.data.fd = listenfd;
ev.events = EPOLLIN | EPOLLET;
//注册epoll事件
epoll_ctl(epfd, EPOLL_CTL_ADD, listenfd, &ev);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(6666);
bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
listen(listenfd, LISTENQ);
maxi = 0; //useless
for (;;)
{
nfds = epoll_wait(epfd, events, 20, 0);
for (i = 0; i < nfds; ++i)
{
if (events[i].data.fd == listenfd) //如果新监测到一个SOCKET用户连接到了绑定的SOCKET端口,建立新的连接。
{
connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &clilen);
// printf("\n当前连接的客户端 ip: %s port: %d", inet_ntoa(cliaddr.sin_addr), ntohs(cliaddr.sin_port));
if (connfd < 0)
{
perror("connfd<0");
exit(1);
}
//setnonblocking(connfd);
char *str = inet_ntoa(cliaddr.sin_addr);
// printf("accept a connection from %s\n", str);
ev.data.fd = connfd;
ev.events = EPOLLIN | EPOLLET;
printf("当前连接的客户端 ip: %s port: %d\n", inet_ntoa(cliaddr.sin_addr), ntohs(cliaddr.sin_port));
epoll_ctl(epfd, EPOLL_CTL_ADD, connfd, &ev);
}
else if (events[i].events & EPOLLIN)
//如果是已经连接的用户,并且收到数据,那么进行读入。
{
if ((sockfd = events[i].data.fd) < 0)
continue;
if ((n = read(sockfd, BUF, MAXLINE)) < 0)
{
if (errno == ECONNRESET)
{
close(sockfd);
events[i].data.fd = -1;
}
else
printf("readline error\n");
}
else if (n == 0)
{
close(sockfd);
events[i].data.fd = -1;
}
BUF[n] = '\0';
write(sockfd, BUF, n);
ev.data.fd = sockfd;
ev.events = EPOLLOUT | EPOLLET;
//读完后准备写
epoll_ctl(epfd, EPOLL_CTL_MOD, sockfd, &ev);
}
else if (events[i].events & EPOLLOUT) // 如果有数据发送
{
sockfd = events[i].data.fd;
write(sockfd, BUF, n);
ev.data.fd = sockfd;
ev.events = EPOLLIN | EPOLLET;
//写完后,这个sockfd准备读
epoll_ctl(epfd, EPOLL_CTL_MOD, sockfd, &ev);
}
}
}
return 0;
}