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

最近在学习unix网络编程,从卷一开始看,跟着书,敲了下代码。在这里记录下遇到的问题。

前言

书中源码,采用了作者很多自己写的函数,都在udp.h这个文件里。直接调库的话,显得太业余,去读他的源码,对于刚开始的人来说也太难了吧。所以这里采用自己参考源码,微微修改的方式来学习。

代码

先贴上代码吧;
我自己把需要的宏定义模仿作者放在另一个头文件中。
mfs.h

#include<string.h>
#define MAXLINE 4096
#define bzero(ptr ,n) memset(ptr, 0,n);
#define	LISTENQ		1024
#define MAXLINE		4096

server.cpp

#include "mfs.h"
#include <time.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>

int main(int argc, char **argv){
    int     listenfd,connfd;
    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);//host to net 32位long
    servaddr.sin_port=htons(2020);//host to net 16位

   bind(listenfd, ( struct sockaddr *) &servaddr, sizeof(servaddr));
    listen(listenfd ,LISTENQ);
    for( ; ; ){
        connfd =accept(listenfd, (sockaddr *)NULL, NULL);
        ticks =time(NULL);
       //替代sprintf函数,第二个参数设置的缓冲区大小范围
       	snprintf(buff, sizeof(buff), "%.24s\r\n",ctime(&ticks));
        write(connfd, buff, strlen(buff));
        close(connfd);
    }

}

client.cpp

#include <iostream>
#include <unistd.h>
#include "mfs.h"
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
using namespace std;
int main(int argc, char **argv){
    int   sockfd, n;
    char  recvline[MAXLINE +1];
    struct sockaddr_in servaddr;
   //输入格式错误
    if(argc !=2){
	 cout<<"usage :a.out<IPaddress>"<<endl;
        return -1;
    }
    //申请sockfd
    if( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) <0){
        perror("socket error");
        return -1;
    }
    //memset初始化地址空间
    bzero(&servaddr ,sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port =htons(2020);
    //inet_pton是一个IP地址转换函数,可以在将点分文本的IP地址转换为二进制网络字节序”的IP地址,把 argv[1] 转换后存放在 servaddr.sin_addr
    if(inet_pton(AF_INET, argv[1],&servaddr.sin_addr) <=0){
       perror("inet_pton error for %s",argv[1]);
        return -1;
    }
    //参数sockfd 的socket 连至参数serv_addr 指定的网络地址。结构sockaddr请参考bind()。参数addrlen为sockaddr的结构长度。
    if(connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) <0){
        perror("connect error");
        return -1;
    }
    while( (n= read(sockfd, recvline, MAXLINE)) >0){
        recvline[n] =0;
        if(fputs(recvline, stdout) ==EOF)
            cout<<"fputs error"<<endl;
    }
    if(n<0)
    cout<<"read error"<<endl;
    exit(0);
}

编译

需要先编译mfs.h,ubuntu编译链接自己的头文件
编译server.cpp:g++ -o server server.cpp mfs.o
执行:./server
编译client.cpp :g++ -o client client.cpp mfs.o
执行:./client 127.0.0.1

遇到的问题

1、端口号原文用的是13但1024以下的都需要root权限,所以我改成了2020。否则报错:connection refuse
2、客户端不需要blind,
blind 由bind() 函数的定义与作用——
将一本地地址与一套接口捆绑。本函数适用于未连接的数据报或流类套接口,在 connect()或listen()调用前使用。当用socket()创建套接口后,它便存在于一个名字空间(地址族)中,但并未赋名。bind()函数通过给一个未命名套接口分配一个本地名字来为套接口建立本地捆绑(主机地址/端口号)。
服务端指定了接受连接的端口,客户端只需要通过connect()知道怎么连接服务器就好,而对于本机采用哪个端口连接并不关心。如果客户端采用的blind的话,就绑定一端口,可能会造成端口冲突,(但也不是不行)
3、其他问题都在注释上了。

某些混乱的API

inet_pton和inet_ntop

用于点分字符类型到二进制网络字节序的转换

htonl、htons、ntohs等等

用于主机字节序和网络字节序之间的转换,转换前后都是unint_t
h代表主机字节序、n代表网络字节序,s代表短整型16位一般用于端口号的转换,l代表长整型32位,一般用于ipv4的转换。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值