简单的时间获取C/S程序

unp网络编程卷一



实现简单的获取时间的客户机/服务器程序


本章节出现的一些函数和结构体信息如下:


客户机端:

结构体:structsockaddr_in servaddr;

structsockaddr_in

{

shortsin_family; /* AF_INET(地址族)PF_INET(协议族)*/

unsignedshort sin_port; /* Port number(必须要采用网络数据格式,普通数字可以用htons()函数转换成网络数据格式的数字)*/

structin_addr sin_addr; /* Internet address */

unsignedchar sin_zero[8]; /* Same size as struct sockaddr没有实际意义,只是为了跟SOCKADDR结构在内存中对齐*/

};


结构体总共16个字节


长度(8位)

AF_INET8位)

端口号(16位)

IPV4地址(32位)

空余(64位)







主要函数原型:socket(),bzero(),connect(),read()


其余函数:htons(),inet_port()


函数说明:



int socket(intdomain, inttype, intprotocol);

函数功能:创建一个套接字并返回一个整数描述符,供后面的函数调用(如connect(),read())。

函数返回值:若创建成功则返回一个小整数描述符,若失败则返回一个负值

第一个参数 domain表示协议类型 一般为AF_INET

第二个参数 type表示要创建的套接字类型。流套接字类型为SOCK_STREAM、数据报套接字类型为SOCK_DGRAM

第三个参数 protocol表示应用程序所使用的通信协议,一般取0



void bzero(void *s, int n);

函数功能:将一段内存单元清空

第一个参数s为指向单元的指针

第二个参数位要清空内存的大小



int connect (int sockfd, struct sockaddr * serv_addr, int addrlen);

函数功能:将本机与第二个参数所描述的服务器建立TCP连接。

第一个参数为之前建立的套接字的描述符

第二个参数为想要连接的目的主机的信息结构体的指针

第三个参数为第二个参数结构体的大小



ssize_t read(int sockfd, void *buf, int nbyte);

函数功能:从目的处读取信息(此处为26个字节的时间信息)

函数返回值:正常情况下函数会返回实际读取的字节大小,若发生错误返回-1

第一个参数为之前建立的套接字的描述符

第二个参数为目的缓冲区的首地址

第三个参数为想要读出的数据大小



u_short htons( u_short hostshort);

函数功能:将一个本地端的整数转换为网络端整数

参数 为要需转换的无符号短整数



int inet_pton(int af, const char *src, void *dst);

函数功能:将一个字符形式的ip地址转换为数字

第一个参数表示协议一般为AF_INET或者AF_INET6

第二个参数表示指向字符型ip地址的指针

第三个参数表示存放ip地址转换后的目的地址



客户机程序如下:

#include<unp.h>

int main(int argc, char **argv)
{
	int 	sockfd, n, i = 0;
	char 	recvline[MAXLINE + 1];
	struct	sockaddr_in	servaddr;
	
	if (argc != 2)
		err_quit("usage: a.out <IPaddress>");
	
	if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
		err_sys("socket error");

	bzero(&servaddr, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_port   = htons(9999);	/*daytime server*/
	
	if (inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0)
		err_quit("inet_pton error for %s", argv[1]);

	if (connect(sockfd, (SA *) &servaddr, sizeof(servaddr)) < 0)
		err_sys("connect error");
	
	while ( n = read(sockfd, recvline, MAXLINE) > 0) 
	{
		recvline[n] = 0;		/* null terminate */
		i++;	
		if(fputs(recvline, stdout) == EOF)
			err_sys("fputs error");
		
	}
	
	printf("n= %d \n", i);

	if(n < 0)
		err_sys("read error");
	printf("\n program terminition!\n");
	exit(0);
}



服务器端:

主要用到的函数有:bind(),listen(),accept()

其他函数:snprintf(),write()



int bind(int sockfd, const struct sockaddr * my_addr, socklen_t addrlen);

第一个参数为建立的套接字描述符

第二个参数为接受连接主机的信息结构体的指针(INADDR_ANY)表示接受任何ip地址从指定端口访问

第三个参数表示结构体的大小



int listen(int s, int backlog);

第一个参数为建立的监听套接字描述符

第二个参数表示TCP模块允许的已完成三次握手过程(TCP模块完成)但还没来得及被应用程序accept的最大链接数.



int accept(int sockfd, void * addr, int * addrlen);

第一个参数sockfd是和listen()中一样的套接字描述符。

第二个参数addr是个指向局部的数据结构通用地址结构信息的指针。

第三个参数addrlen是个局部的整形变量。



int snprintf(char *str, size_t size, const char *format, ...);

这个函数类似与printf(),只是相较之而言,多了前面两个参数,前面两个参数

第一个表示要输出的目的缓冲区的地址,第二个表示缓冲区的大小



ssize_twrite (int fd,const void * buf,size_t count);

这个函数与read函数类似,不过功能不同

write函数将缓冲区数据写入套接字指向的机器

说明:此处应当注意到,当前的套接字与listen函数中视用的套接字并非同一个,这是由于这两个套接字各有功效,listen套接字只监听窗口但并不涉及传输数据。调用accept()将返回一个新的套接字文件描述符。这样就有两个套接字,原来的一个还在侦听你的那个端口,新的套接字在准备发送和接收数据。

服务器端代码如下:

#include<unp.h>

int main(int argc, char **argv)
{
	int    listenfd, connfd, i;
	struct sockaddr_in servaddr;
	char   buff[MAXLINE];
	time_t ticks;

	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(9999);
	
	Bind(listenfd, (SA *) &servaddr, sizeof(servaddr));
	
	Listen(listenfd, LISTENQ);

	for( ; ; )
	{
		connfd = Accept(listenfd, (SA *) NULL, NULL); 
		
		ticks = time(NULL);
		snprintf(buff, sizeof(buff), "%.24s\r\n", ctime(&ticks));
		for(i = 0; i < strlen(buff); i++)
		{
			Write(connfd, &buff[i], 1);
		}
	}
}





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值