一个简单的回射服务器的步骤:
1.客户端从标准输入读入一行文本,并写给服务器。
2.服务器端从网络输入读入这行文本,并返回给客户
3.客户端从网络输入读入这行反射文本,并显示在标准输出上。
如图:
服务器端的反射程序:
#include "unp.h"
int main(int argc, char **argv)
{
int listenfd, connfd;
pid_t childpid;
socklen_t clilen;
/*sockaddr_in为ipv4 套接口地址结构 详解参照3.2节*/
struct sockaddr_in cliaddr, servaddr;
/*Socket函数原型int socket (int family, int type, int protocol);protocol为0时
,以选择给定family和type组合的系统缺省值。参照 4.2节,*/
listenfd = Socket(AF_INET, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
/*考虑主机字节序和网络字节间的相互转换。参照3.4节*/
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(SERV_PORT);
/*把一个本地协议地址(&servaddr)赋予一个套接口(listenfd) 4.4节。赋予之前一定要先将(&servaddr)转
化成指向通用套接口地址结构的指针 3.2节。对于将地址转化成指向具体地址结构的指针可参照:将数值存储到指定的内存地址。*/
Bind(listenfd, (SA *) &servaddr, sizeof(servaddr));
/*listen把一个未连接的套接口转换成一个被动套接口,指示内核应该接受指向该套接口的连接请求。4.5节*/
Listen(listenfd, LISTENQ);
for ( ; ; ) {
clilen = sizeof(cliaddr);
/*Accept的第一个参数listenfd称为监听套接口描述字,是由socket创建;Accept的返回值connfd为已连接套接口描述字。4.6节*/
connfd = Accept(listenfd, (SA *) &cliaddr, &clilen);
if ( (childpid = Fork()) == 0) { /* child process */
Close(listenfd); /*child process close listening socket */
str_echo(connfd); /* process the request */
exit(0);
}
Close(connfd); /* parent closes connected socket */
}
}
将数值存储到指定的内存地址:
假设现在需要往内存 0x12ff7c地址上存入一个整型数 0x100。 我们怎么才能做到呢?我们知道可以通过一个指针向其指向的内存地址写入数据,那么这里的内存地址 0x12ff7c 其本质不就是一个指针嘛。所以我们可以用下面的方法:
int *p = (int *)0x12ff7c;/* p值则为0x12ff7c */
*p = 0x100;
TCP回射服务器程序:str_echo 函数
#include "unp.h"
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 && errno == EINTR)
goto again;
else if (n < 0)
err_sys("str_echo: read error");
}