1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
#include<<netinet/in.h>
typedef
uint32_t in_addr_t;
struct
in_addr
{
in_addr_t s_addr;
//即uint32_t s_addr 32位的IPv4网络字节序
};
typedef
unsigned
short
int
sa_family_t;
#define __SOCKADDR_COMMON(sa_prefix) sa_family_t sa_prefix##family //C语言中#的用法
struct
sockaddr
{
__SOCKADDR_COMMON (sa_);
//即unsigned short int sin_family; 地址族
char
sa_data[14];
//特定的协议地址
};
struct
sockaddr_in
{
uint8_t sin_len;
//该结构体的长度
__SOCKADDR_COMMON (sin_);
//即unsigned short int sin_family;协议族 IPv4为AF_INET
in_port_t sin_port;
//端口号
struct
in_addr sin_addr;
//32位IPv4网络字节序地址
unsigned
char
sin_zero[
sizeof
(
struct
sockaddr) - __SOCKADDR_COMMON_SIZE -
sizeof
(in_port_t) -
sizeof
(
struct
in_addr)];
//填充对齐位
};
//一般情况下上述结构体可以具体化如下:
struct
sockaddr_in
{
uint8_t sin_len;
//带符号8位整数地址结构长度
sa_family_t sin_family;
//协议族,IPv4为AF_INET
in_port_t sin_port;
//端口号
struct
in_addr sin_addr;
//32位IPv4网络字节序地址
char
sin_zero[8];
//填充对齐位
};
|
#include<sys/socket.h>
struct
sockaddr
{
uint8_t sa_len;
//该结构体的长度
sa_family_t sa_family;
//地址族
char
sa_data[14];
//特定的协议地址
};
|
1
2
|
struct
sockaddr_in serv;
//定义一个套接字地址结构体变量
connect (sockfd, (
struct
sockaddr *) &serv,
sizeof
(serv));
|
1
2
3
|
struct
sockaddr_un cli;
//定义一个套接字地址结构体变量
socklen_t len =
sizeof
(cli);
//该结构体的大小
getpeername(unixfd,(
struct
sockaddr *)&cli,&len);
//len可能会被改变
|
1
2
3
4
5
|
#include <netinet/in.h>
uint16_t htons(uint16_t host16bitvalue);
//将16位主机字节序转化为相应的网络字节序
uint32_t htonl(uint32_t host32bitvalue);
//将32位主机字节序转化为相应的网络字节序
uint16_t ntohs(uint16_t net16bitvalue);
//将16位网络字节序转化为相应的主机字节序
uint32_t ntohl(uint32_t net32bitvalue);
//将32位网络字节序转化为相应的主机字节序
|
#include <strings.h>
void
bzero(
void
*dest,
size_t
nbytes);
//将字符串初始化为0
void
bcopy(
const
void
*src,
void
*dest,
size_t
nbytes);
//拷贝字符串
int
bcmp(
const
void
*ptrl,
const
void
*ptr2,
size_t
nbytes);
//比较两个字符串,若相等则返回0
void
*
memset
(
void
*dest,
const
void
*c,
size_t
len);
//作用是在一段内存块中填充某个给定的值,它是对较大的结构体或数组进行清零操作的一种最快方法
void
*
memcpy
(
void
*dest,
const
void
*src,
size_t
nbytes);
//从源src所指的内存地址的起始位置开始拷贝nytes个字节到目标dest所指的内存地址的起始位置中
int
memcmp
(
const
void
*ptrl,
const
void
*ptr2,
size_t
nbytes);
//比较两个字符串的前nbytes个字符,若相等则返回0
//补充说明:当源字节串与目标字节串重叠时,bcopy能够正确处理,但是memcpy的操作结果却不可知.
|
#include<arpa/inet.h>
in_addr_t inet_addr(
const
char
*strptr);
//若成功,返回32位二进制的网络字节序地址
char
*inet ntoa(
struct
in_addr inaddr);
//将一个32位的网络字节序二进制IPv4地址转换成相应的点分十进制数串
|
#include "unp.h"
int
main(
int
argc,
char
**argv)
{
union
//注意这是共用体
{
short
s;
char
c[
sizeof
(
short
)];
}un;
un.s = 0x0102;
if
(
sizeof
(
short
) == 2)
{
if
(un.c[0] == 1 && un.c[1] == 2)
//高字节在高地址 低字节在低地址
printf
(
"大端\n"
);
else
if
(un.c[0] == 2 && un.c[1] == 1)
//低字节在高地址 高字节在低地址
printf
(
"小端\n"
);
else
printf
(
"未知\n"
);
}
else
printf
(
"sizeof(short) = %d\n"
,
sizeof
(
short
));
exit
(0);
}
|
//从一个描述符读取n个字节
ssize_t readn(
int
fd,
void
* vptr,
size_t
n)
{
size_t
nleft = n;
//记录还剩下多少字节数没读取
ssize_t nread;
//记录已经读取的字节数
char
* ptr = vptr;
//指向要读取数据的指针
while
(nleft > 0)
//还有数据要读取
{
if
(nread = read(fd,ptr,nleft) < 0)
if
(erron == EINTR)
//系统被一个捕获的信号中断
nread = 0;
//再次读取
else
return
-1;
//返回
else
if
(nread == 0)
//没有出错但是也没有读取到数据
break
;
//再次读取
nleft -= nread;
//计算剩下未读取的字节数
ptr += nread;
//移动指针到以读取数据的下一个位置
}
return
(n-nleft);
//返回读取的字节数
}
/**************************************************************************************************/
//从一个描述符读文本行,一次一个字节
ssize_t readline(
int
fd,
void
* vptr,
size_t
maxlen)
//一个字节一个字节地读取
{
ssize_t rc;
//每次读取的字符
ssize_t n;
//读取的次数也即读取字符串的长度
char
c;
//
char
* ptr = vptr;
//指向要读取的数据的指针
for
(n = 1;n < maxlen; n++)
{
again:
if
((rc = read(fd,&c,1)) == 1)
{
*ptr++ = c;
//移动指针
if
(c ==
'\n'
)
//换行符
break
;
//跳出循环
else
if
(rc == 0)
//结束
*ptr = 0;
//字符串以0结尾
return
(n-1);
//返回读取的字节数 末尾的0不算
}
else
{
if
(erron == EINTR)
goto
again;
//重新读取
return
(-1)
}
}
*ptr=0;
return
n;
}
/**************************************************************************************************/
//往一个描述符写n个字节
ssize_t writen(ind fd,
const
void
* vptr,
size_t
n)
{
size_t
nleft = n;
//还需要写入的字节数
ssize_t nwritten;
//每次写入的字节数
const
char
* ptr = vptr;
//指向要写入的数据的指针
while
(nleft > 0)
{
if
((nwritten = write(fd,ptr,nleft)) <= 0)
{
if
(nwritten < 0 && erron == EINTR)
nwritten = 0;
else
return
-1;
}
nleft -= nwritten;
//计算还需要写入的字节数
ptr += nwritten;
//移动数据指针
}
return
n;
}
|
#include <sys/socket.h>
int
socket(
int
family,
int
type, iny potocol);
|
int
connect(
int
sockfd,
const
struct
sockaddr* servaddr,socklen_t addrlen);
|
#include<sys/socket.h>
int
bind(
int
sockfd,
const
struct
sockaddr* myaddr,socklen_t addrlen);
|
#include<sys/socket.h>
int
listen(
int
sockfd,
int
backlog);
|
int
accept(
int
sockfd,
struct
sockaddr* Cliaddr,socklen_t* Addrlen);
|
#include <sys/socket.h>
int
close(
int
sockfd);
|
#include <sys/socket.h>
int
getsockname(
int
sockfd,
struct
sockaddr *localaddr, socklen_t *addrlen);
int
getpeername(
int
sockfd,
struct
sockaddr *peeraddr, socklen_t *addrlen);
|
int
main()
{
int
listenfd;
//监听套接字
int
connfd;
//连接套接字
pid_t childpid;
//线程ID
socklen_t clilen;
//客户地址结构大小
struct
sockaddr_in servaddr;
//服务器地址结构信息
struct
sockaddr_in ciladdr;
//客户地址结构信息
listenfd=Socket(AF_INET,SOCK_STREAM,0);
//创建套接字
bzero(&servaddr,
sizeof
(servaddr));
//初始化
servaddr.sin_family=AF_INET;
//设置本服务器的协议族
servaddr.sin_addr.s_addr=htonl(INADDR_ANY);
//设置本服务器的IP地址
servaddr.sin_port=htons(SERV_PORT);
//设置本服务器的端口号
Bind(listenfd,(
struct
sockaddr*)&servaddr,
sizeof
(servaddr));
//绑定套接字
Listen(listedfd,LISTENQ);
//开始监听
while
(1)
//死循环
{
clilen=
sizeof
(cliaddr);
//计算结构体大小
connfd=Accept(listenfd,(
struct
sockaddr*)&cliaddr,&clilen);
//接受请求并记录下所请求客户的相关信息:IP地址+端口号
if
((childpid = Fork()) == 0)
//创建线程
{
Close(listenfd);
//关闭连接
str_echo(connfd);
exit
(0);
}
close(connfd);
//关闭连接
}
}
void
str_echo(
int
sockfd)
{
ssize_t n;
char
buf[MAXLINE];
again:
while
((n = read(sockfd,buf,MAXLINE))>0)
Writen(sockfd,buf,n);
if
(n<0 && erron==EINTR)
//出错了
goto
again;
else
if
(n<0)
err_sys(
"str_echo:read error"
);
}
|
int
main(
int
argc,
char
** argv)
{
int
sockfd;
//套接字
struct
sockaddr_in servaddr;
//服务器地址结构信息变量
if
(argc!=2)
err_quit(
"请输入点分十进制格式的IP地址"
);
sockfd=Socket(AF_INET,SOCK_STREAM,0);
//创建一个连接
bzero(&servaddr,
sizeof
(servaddr));
//填写远程服务器的相关信息
servaddr.sin_family = AF_INET;
//协议族
setvaddr.sin_port=htons(SERV_PORT);
//服务器端口号
inet_pton(AF_INET,argv[1],&seraddr.sin_addr);
//IP地址格式转换
connect(sockfd,(
struct
sockaddr *)&servaddr,
sizeof
(servaddr));
//向服务器发起连接请求
str_cli(stdin,sockfd);
exit
(0);
}
}
void
str_cli(
FILE
* fp,
int
sockfd)
{
char
sendline[MAXLINE];
char
recvline[MAXLINE];
while
(Fgets(sendline,MAXLINE,fp)!=NULL)
//等待用户数据输入
{
Write(sockfd,recvline,
strlen
(sendline));
//向服务器发送用户所输入的数据
if
(Readline(sockfd,recvline,MAXLINE)==0)
//读取服务器发送过来的数据
err_quit(
"str_cli:server treminated prematurely"
);
Fputs(recvline,stdout);
//输出
}
}
|
#include<sys/select.h>
#include<sys/time.h>
struct
timeval
{
longtv_sec;
longtv_usec;
};
int
select(
int
maxfdp1,fd_set* readset,fd_set* writeset,fd_set* exceptset,
const
struct
timeval* timeout);
|
#include "unp.h"
void
str_cli(
FILE
*fp,
int
sockfd)
{
int
maxfdp1;
fd_set rset;
char
sendline[MAXLINE], recvline[MAXLINE];
FD_ZERO(&rset);
for
( ; ; )
{
FD_SET(fileno(fp), &rset);
FD_SET(sockfd, &rset);
maxfdp1 = max(fileno(fp), sockfd) + 1;
Select(maxfdp1, &rset, NULL, NULL, NULL);
if
(FD_ISSET(sockfd, &rset))
{
if
(Readline(sockfd, recvline, MAXLINE) == 0)
err_quit(
"str_cli: server terminated prematurely"
);
Fputs(recvline, stdout);
}
if
(FD_ISSET(fileno(fp), &rset))
//可读
{
if
(Fgets(sendline, MAXLINE, fp) == NULL)
return
;
Writen(sockfd, sendline,
strlen
(sendline));
}
}
}
|
#include<sys/socket.h>
int
shutdown(intsockfd,inthowto);
|
#include "unp.h"
void
str_cli(
FILE
*fp,
int
sockfd)
{
int
maxfdp1, stdineof;
fd_set rset;
char
buf[MAXLINE];
int
n;
stdineof = 0;
FD_ZERO(&rset);
for
( ; ; )
{
if
(stdineof == 0)
FD_SET(fileno(fp), &rset);
FD_SET(sockfd, &rset);
maxfdp1 = max(fileno(fp), sockfd) + 1;
Select(maxfdp1, &rset, NULL, NULL, NULL);
if
(FD_ISSET(sockfd, &rset))
{
if
( (n = Read(sockfd, buf, MAXLINE)) == 0)
{
if
(stdineof == 1)
return
;
else
err_quit(
"str_cli: server terminated prematurely"
);
}
Write(fileno(stdout), buf, n);
}
if
(FD_ISSET(fileno(fp), &rset))
{
if
( (n = Read(fileno(fp), buf, MAXLINE)) == 0)
{
stdineof = 1;
Shutdown(sockfd, SHUT_WR);
FD_CLR(fileno(fp), &rset);
continue
;
}
Writen(sockfd, buf, n);
}
}
}
|
#include "unp.h"
int
main(
int
argc,
char
**argv)
{
int
i, maxi, maxfd, listenfd, connfd, sockfd;
int
nready, client[FD_SETSIZE];
ssize_t n;
fd_set rset, allset;
char
buf[MAXLINE];
socklen_t clilen;
struct
sockaddr_in cliaddr, servaddr;
listenfd = Socket(AF_INET, SOCK_STREAM, 0);
bzero(&servaddr,
sizeof
(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(SERV_PORT);
Bind(listenfd, (SA *) &servaddr,
sizeof
(servaddr));
Listen(listenfd, LISTENQ);
maxfd = listenfd;
maxi = -1;
for
(i = 0; i < FD_SETSIZE; i++)
client[i] = -1;
FD_ZERO(&allset);
FD_SET(listenfd, &allset);
for
( ; ; )
{
rset = allset;
nready = Select(maxfd+1, &rset, NULL, NULL, NULL);
if
(FD_ISSET(listenfd, &rset))
{
clilen =
sizeof
(cliaddr);
connfd = Accept(listenfd, (SA *) &cliaddr, &clilen);
#ifdef NOTDEF
printf
(
"new client: %s, port %d\n"
,
Inet_ntop(AF_INET, &cliaddr.sin_addr, 4, NULL),
ntohs(cliaddr.sin_port));
#endif
for
(i = 0; i < FD_SETSIZE; i++)
if
(client[i] < 0)
{
client[i] = connfd;
break
;
}
if
(i == FD_SETSIZE)
err_quit(
"too many clients"
);
FD_SET(connfd, &allset);
if
(connfd > maxfd)
maxfd = connfd;
if
(i > maxi)
maxi = i;
if
(--nready <= 0)
continue
;
}
for
(i = 0; i <= maxi; i++)
{
if
( (sockfd = client[i]) < 0)
continue
;
if
(FD_ISSET(sockfd, &rset))
{
if
( (n = Read(sockfd, buf, MAXLINE)) == 0)
{
Close(sockfd);
FD_CLR(sockfd, &allset);
client[i] = -1;
}
else
Writen(sockfd, buf, n);
if
(--nready <= 0)
break
;
}
}
}
}
|