2020/2/15学习Linux Socket时遇到的问题

1. C语言中int main(int argc, char *argv[])中这两个参数是什么意思?

    argc:命令行参数的个数,默认值是1

    argv:char类型的指针数组,用于保存命令行参数;argv[0]是带路径的程序名称,argv[1]是dos命令行中执行程序名后的第一个字符串,argv[2]是第二个字符串,以此类推.....

这两个参数的作用是:可以接收命令行中输入的参数【好方便啊!】

2. 设置服务器端Socket的地址

【如果只设定服务器机的一个ip地址】

这样设置:serveraddr是结构体sockaddr_in的实例;

而在sockaddr_in结构体中有一个成员sin_addr ,它是结构体in_addr的实例,

地址就保存在结构体sockaddr_in中的结构体sin_addr中的s_addr成员中——

serveraddr.sin_addr.s_addr = htons("192.168.0.10");

【如果要让服务器上的所有ip地址都得到连接请求】

需要一个特殊的地址 

#define INADDR_ANY (uint32_t)0x00000000

serveraddr.sin_addr.s_addr = INADDR_ANY;

3. Socket TCP编程 服务端

#include <netdb.h>
#include <sys/socket.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <signal.h>
#include <time.h>

//#define INADDR_ANY (uint32_t)0x00000000
int sockfd;

void sig_handler(int signo)
{
    if(signo == SIGINT){
        printf("server close\n");
        /*step 6 close socket*/
        close(sockfd);
        exit(1);//0 or 1 all can close
    }
}

/*output client's messages */
void out_addr(struct sockaddr_in *clientaddr)
{
    int port = ntohs(clientaddr->sin_port);//net to host
    char ip[16];
    memset(ip,0,sizeof(ip));
    inet_ntop(AF_INET, &clientaddr->sin_addr.s_addr, ip, sizeof(ip));//net to Dot decimal(same as 192.168.0.1)
    printf("client: %s(%d) connected\n", ip, port);
}

void do_service(int fd)
{
    long t = time(0);//write server's system time to client
    char *s = ctime(&t);
    size_t size = strlen(s) * sizeof(char);
    if(write(fd, s, size) != size){
        perror("write error");
    }
}

int main(int argc, char *argv[])
{
    if(argc < 2){
        printf("usage: %s #port\n", argv[0]);//print program's name
        exit(1);
    }
    if(signal(SIGINT, sig_handler) == SIG_ERR){//SIGINT:ctrl+C can end ; signal function get SIG_ERR if error
        perror("signal sigint error");         //perror function is defined in <stdlib.h>,we can see" str: error message"
        exit(1);
    }

    /*step 1 creat socket
     *socket is a struct in kernel
     *AF_INET: IPV4
     *SOCK_STREAM: tcp protocol(udp: SOCK_DGRAM)
     **/
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    
    /*step 2 bind()
     *bound with socket and address(ip\port\intnet type)
     *sockaddr_in is special net_struct for internet */
    struct sockaddr_in serveraddr;
    memset(&serveraddr, 0, sizeof(serveraddr));  //clear
    serveraddr.sin_family = AF_INET;              //IPV4(Host byte order is ok)
    serveraddr.sin_port   = htons(atoi(argv[1]));//port from terminal(atoi:string to int)(htons:Host to Network byte order 16bit)
    serveraddr.sin_addr.s_addr = INADDR_ANY;     //htons("192.168.0.10")
    if(bind(sockfd, (struct sockaddr*)&serveraddr, sizeof(serveraddr)) < 0){//cast as common address type : sockaddr
        perror("bind error");
        exit(1);
     }

    /*step 3 listen()
     *tell system to accept connecting request (in server port)
     *put connecting request to queue*  (10 is the length of queue)
     */
    if(listen(sockfd, 10) < 0){
        perror("listen error");
        exit(1);    
    }
    
    /*step 4 accept()
     *get a connection and return the new socket file descriptor(sockfd)
     *This sockfd(client's fd) is different from the sockfd in step 1(server's fd)
     */
    struct sockaddr_in clientaddr;
    socklen_t clientaddr_len = sizeof(clientaddr);//This is a pointer so we need to use & to get the message
    while(1){
        int fd = accept(sockfd,    (struct sockaddr*)&clientaddr, &clientaddr_len);
        if(fd < 0) {
             perror("accept error");
            continue;
        }
    

    /*step 5 IO function: read/write 
     */
    out_addr(&clientaddr);
    do_service(fd);
    /*step 6 close socket
     */
    close(fd);//client's sockfd

    }

    return 0;
}

以上程序报错/警告如下:

warning1: “xxx” redefined

INADDR_ANY这个宏在多个文件中重复定义了,可能包含在了多个.h文件中。

解决办法:既然在.h文件中已经有过了宏定义,我就把自己定义的那行注释掉了

warning2: implicit decleration of function 'xxx' 诸如此类报错都是调用的函数未声明造成的。

解决办法:开头加上#include <arpa/inet.h>

最后运行一下~由于没有客户端连进来,服务器一直保持监听状态,ctrl+C可以结束进程。

采用本机的另一个终端中的telnet测试程序,最终返回给客户端一个服务器端的系统时间

采用浏览器与测试程序通信,最终浏览器客户端显示了服务器的系统时间

注意:

1. telnet、http是应用层协议,但可以进行数据通信,架构在TCP协议之上;

2. 127.0.0.1是本机ip,其他机器的客户端想要连接本机的服务器,必须要获取本机真正的ip地址——ifconfig;

3. 服务器端收到的客户端端口号,是系统自动分配的(35304),每次连接都不一样。

明天更新客户端的部分

学习教程来自:b站av36871598

发布了3 篇原创文章 · 获赞 3 · 访问量 76

猜你喜欢

转载自blog.csdn.net/Xinyue_Lu/article/details/104326819
今日推荐