2-socket的实践到内核--socket使用IP地址通讯

来源:互联网 发布:均衡器软件 编辑:程序博客网 时间:2024/06/14 23:05
前面一章我们看到在本机内创建一个socket,如果创建socket时指定为AF_UNIX时就为unix和linux内部的socket,而如果指定为AF_INET时则为unix和linux的网络socket,我们一定要注意这二者的区别,当然还有其他的种类,因为避免太学术上排列,我在这里列出来相信大家也记不住,上面二种是最重要的也是最常用的,因此列在这里,其他几种不太常用,okay,我们再看一下socket的地址,如果建立了socket而没有指定地址是不通被其他socket连接到的,就象linux内核情景分析书中形容的那样“只有电话没有号码”,所以我们看到前边那节的例子中用的是sockaddr_un地址结构,它是专用于unix内部的socket的“电话号码”,要想与其他操作系统通讯应用使用sockaddr_in结构,它专用于互联网中使用,当然还有一种用于使用ip的地址结构in_addr,但是它只含一个ip地址不象sockaddr_in那样还有端口和网域,所以我们也在练习中看到使用前面二种,实际开发中也是这二种。有了这些基础知识下面我们看使用IP地址在本机上通讯的练习,首先是服务器端的代码:


#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>

int main()
{
    int server_sockfd, client_sockfd;
    int server_len, client_len;
    struct sockaddr_in server_address;
    struct sockaddr_in client_address;

下面创建一个网络使用的socket

    server_sockfd = socket(AF_INET, SOCK_STREAM, 0);

为这个创建的socket指定IP地址和端口,ip地址是127.0.0.1而端口则为9734

    server_address.sin_family = AF_INET;
    server_address.sin_addr.s_addr = inet_addr("127.0.0.1");
    server_address.sin_port = 9734;
    server_len = sizeof(server_address);

将“电话号码”赋值给“电话”,即将设定的地址结构与socket挂起钩来,朋友们以后理解指针赋值可以理解为钩子,就象网上有种叫法“钩子函数”实际就是指针函数
    bind(server_sockfd, (struct sockaddr *)&server_address, server_len);


创建一个socket的连接队列监听或者称为等待客户端处的socket来连接

    listen(server_sockfd, 5);
    while(1) {
        char ch;

        printf("server waiting/n");

到达此处时,已经说明客户端的连接请求来到了,下面是接受它的连接请求并将客户端的“电话号码”记录在client_address中。并且通过accept克隆了一个二者保持通讯的socket,为什么要克隆,我们追踪到内核再说,这里函数返回了服务器端与客户端建立连接的socket的ID号
        client_len = sizeof(client_address);
        client_sockfd = accept(server_sockfd,
            (struct sockaddr *)&client_address, &client_len);

使用read和write函数向已经建立的socket接收客户端的一个字符然后再发送回去

        read(client_sockfd, &ch, 1);
        ch++;
        write(client_sockfd, &ch, 1);
        close(client_sockfd);
    }
}

好,我们再看客户端的代码

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>

int main()
{
    int sockfd;
    int len;
    struct sockaddr_in address;
    int result;
    char ch = 'A';

同样要创建一个客户端的socket,然后用这个socket去向服务器的socket连接去

    sockfd = socket(AF_INET, SOCK_STREAM, 0);


为建立的socket设定电话号码,这个电话号码要与服务器端的socket号码一致,准备连接使用
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = inet_addr("127.0.0.1");
    address.sin_port = 9734;
    len = sizeof(address);

使用电话号码向服务器端拨号,请求服务器的socket连接

    result = connect(sockfd, (struct sockaddr *)&address, len);

    if(result == -1) {
        perror("oops: client2");
        exit(1);
    }

到这里我们连接成功了,就对建立的socket发送一个字符然后接收服务器端返回的一个字符并打印了到控制台

    write(sockfd, &ch, 1);
    read(sockfd, &ch, 1);
    printf("char from server = %c/n", ch);
    close(sockfd);
    exit(0);
}

这里我们运行一下程序

[root@localhost wumingxiaozu]# ./server2 &
[root@localhost wumingxiaozu]# ./client2
char from server = B

好,因为socket的通讯要比我们说的消息队列、共享内存和信号量复杂的多,因此我们要做的这几个练习都是非常必要的,必须在实践上摸清都有那些具体的情况我在深入内核时才会不致于看到“导游地图”时而找不到方向,continue......