Linux _TCP 浅解

网络套接字通信(基于TCP)

  1. 相关头文件
    #include <netinet/in.h>
    #include <arpa/inet.h>
qianjie
  1. 开发步骤
    开发步骤与文件系统套接字相似,区别仅在于:
    1)创建套接字时使用的参数不同
    文件系统套接字,使用的域参数为 AF_UNIX
    网络套接字,使用的域参数为 AF_INET

    2) 套接字所使用的地址类型不同
    文件系统套接字使用的地址类型:struct sockaddr_un
    文件系统套接字使用的地址类型:struct sockaddr_in
    注意:server_addr.sin_addr.s_addr表示IP地址,
    是一个4字节数,而不是字符串,可使用inet_addr函数进行转换
    例:server_addr.sin_addr.s_addr = inet_addr(“127.0.0.1”)

    补充:回环地址(“127.0.0.1”, 即相当于本地的IP地址)
             UNIX和Linux都配置了一个回路网络,在该网络中,只有一个IP地址,即127.0.0.1
    
             INADDR_ANY, 表示该服务器可接受任意IP地址的客户端
    

    3)套接字所使用的地址的设置方式不同
    网络套接字所使用的地址,需要设置端口号和IP地址。
    (1)端口号的设置
    端口号是一个无符号16数
    例: server_addr.sin_port = 9000;

           端口号的选择:
           选择1024以上的任意一个未使用的端口好即可。(1024以内的端口号为系统内部使用)
    
           查看已使用的端口号:
           cat  /etc/services
    
           客户端程序中指定的端口号要与服务器套接字使用的端口号一致
    
     (2) 主机字节序与网络字节序
            不同主机的字节序(大小端格式)可能不同。
            而在网络上传输时,使用统一的网络字节序(大端格式)。
            所以,在设置端口号时,需要进行字节序转换,否则将导致错误。
            (因为,当通过TCP/IP协议传输时,端口号本身也包含在被传输数据中。)
    
            使用inet_addr转换IP地址时,同时自动转换为网络字节序。
    
            主机字节序和网络字节序的转换:
            htonl  把主机的无符号长整形转换为标准的网络字节序
            htons 把足迹的无符号短整形转换为标准的网络字节序
    
            例:server_addr.sin_port = htons(9000);
    

    4)步骤总结:
    基于TCP的网络套接字通信
    服务器端
    (1) 创建一个网络套接字
    (2) 设置服务器地址
    (3) 绑定该套接字,使得该套接字和对应的端口关联起来。
    (4) 创建套接字队列, 保存进入该服务器的客户端请求
    (5) 循环处理客户端请求
    使用accept等待并接收客户端请求
    收到客户端请求后,accept返回一个新的socket(表示该客户端连接)
    使用这个新的socket,对客户端进行“读写“
    处理完毕后,关闭这个新的socket

    客户端
    (1) 创建一个套接字
    (2) 设置服务器地址
    (3) 使用该socket和服务器地址连接服务器(connect)
    (4) 使用该socket发送和接受数据。
    (5) 关闭该socket

    5) 注意
    注意服务器端read的返回值:
    当客户端还没有connect进入时,服务器端的read将被一直阻塞
    当客户端已经connect进入时,
    如果客户端还没有write,服务器端的read也将一直被阻塞
    客户端write成功后,服务器端的read不再阻塞,返回实际读取的字节数。
    当客户端关闭对应套接字时,服务器端的read不再阻塞, 返回0

    实例:server2.c
    client2.c

实例
编写一个实时文字聊天程序。
用网络套接字实现。
客户端和服务器端进行“聊天”
直到客户端或者服务器端输入exit,就结束聊天(即服务器和客户端都退出)

提示:服务器端和客户端,分别使用两个进程或者两个线程,
         用来分别处理发送数据和接受数据。

server3.c
client3.c

demo

client2.c

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

//#define SERVER_SOCKET_FILE  "/tmp/server_socket"

int main(void)
{
    int sockfd;
    struct sockaddr_in server_addr;
    int ret;
    int c;

    // ¥¥Ω®“ª∏ˆÃ◊Ω”◊÷
    sockfd = socket(AF_INET, SOCK_STREAM, 0);

    // …Ë÷√∑˛ŒÒ∆˜µÿ÷∑
    server_addr.sin_family = AF_INET;
    //strcpy(server_addr.sun_path, SERVER_SOCKET_FILE);
    server_addr.sin_addr.s_addr = inet_addr("10.10.0.9"); //"127.0.0.1
    server_addr.sin_port = htons(9000);

    // ¡¨Ω”∑˛ŒÒ∆˜
    ret = connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr));
    if (ret == -1) {
        perror("connet failed!\n");
        exit(1);
    }

    // œÚ∑˛ŒÒ∆˜∑¢ÀÕ ˝æ›
    c = 'm';
    write(sockfd, &c, 1); 

    // ¥”∑˛ŒÒ∆˜∂¡»° ˝æ›
    read(sockfd, &c, 1);

    printf("get data: %c\n"````````````
 c);

    close(sockfd);
    return 0;   
}

server2.c

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

//#define SERVER_SOCKET_FILE  "/tmp/server_socket"

int main(void)
{
    int server_sockfd;
    int client_sockfd;
    char ch;

     //”√”⁄UNIXœµÕ≥ƒ⁄≤øÕ®–≈µƒµÿ÷∑£¨ struct sockaddr_un
     //struct sockaddr_un server_addr;
    struct sockaddr_in server_addr;
    struct sockaddr_in client_addr;
    int client_addr_len;


    /* …æ≥˝“‘«∞µƒŒƒº˛œµÕ≥Ã◊Ω”◊÷À˘∂‘”¶µƒŒƒº˛ */
    //unlink(SERVER_SOCKET_FILE);

    // ¥¥Ω®“ª∏ˆŒƒº˛œµÕ≥Ã◊Ω”◊÷(”√”⁄±æª˙ƒ⁄µƒÕ®–≈)
    //server_sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
    server_sockfd = socket(AF_INET, SOCK_STREAM, 0);

    // …Ë÷√∑˛ŒÒ∆˜µÿ÷∑
    server_addr.sin_family = AF_INET;  //µÿ÷∑µƒ”Ú£¨œ‡µ±”⁄µÿ÷∑µƒ¿‡–Õ, AF_UNIX±Ì æµÿ÷∑Œª”⁄UNIXœµÕ≥ƒ⁄≤ø
    server_addr.sin_addr.s_addr = INADDR_ANY;
    //strcpy(server_addr.sun_path, SERVER_SOCKET_FILE);
    server_addr.sin_port = htons(9000);

    // ∞Û∂®∏√Ã◊Ω”◊÷£¨ πµ√∏√Ã◊Ω”◊÷∫Õ∂‘”¶µƒœµÕ≥Ã◊Ω”◊÷Œƒº˛πÿ¡™∆¿¥°£
    bind(server_sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr));

    // ¥¥Ω®Ã◊Ω”◊÷∂”¡–£¨ ±£¥ÊΩ¯»Î∏√∑˛ŒÒ∆˜µƒøÕªß∂À«Î«Û°£
    listen(server_sockfd, 5);

    // —≠ª∑¥¶¿ÌøÕªß∂À«Î«Û
    while (1) {

        printf("server waiting\n");

        // µ»¥˝≤¢Ω” ’øÕªß∂À«Î«Û
        client_addr_len = sizeof(client_addr);
        //client_sockfd = accept(server_sockfd,  (struct sockaddr*)&client_addr, &client_addr_len);
              client_sockfd = accept(server_sockfd,  0, 0);

        // ∂¡»°øÕªß∂À«Î«Û
        read(client_sockfd, &ch, 1);

        //¥¶¿ÌøÕªß∂À ˝æ›
        ch++;

        // œÚøÕªß∂À∑¢ÀÕΩ·π˚ ˝æ›
        write(client_sockfd, &ch, 1);

        // πÿ±’øÕªß∂ÀÃ◊Ω”◊÷
        close(client_sockfd);       
    }

    return 0;   
}

client3.c

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

#define BUFF_SIZE 1024

int main(void)
{
    int sockfd;
    struct sockaddr_in server_addr;
    int ret;
    int c;
    int pd;
    char buff[BUFF_SIZE];

    // ¥¥Ω®“ª∏ˆÃ◊Ω”◊÷
    sockfd = socket(AF_INET, SOCK_STREAM, 0);

    // …Ë÷√∑˛ŒÒ∆˜µÿ÷∑
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = inet_addr("10.0.0.4");
    //server_addr.sin_port = 9734;
    server_addr.sin_port = htons(9000);

    // ¡¨Ω”∑˛ŒÒ∆˜
    ret = connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr));
    if (ret == -1) {
        perror("connet failed!\n");
        exit(1);
    }

    pd = fork();
    if (pd == -1) {
        perror("create process failed!\n");
        exit(1);
    } else if (pd == 0) {
        // ◊”Ω¯≥Ã∑¢ÀÕ ˝æ›
        while (1) {
            bzero(buff, sizeof(buff));
            fgets(buff, sizeof(buff), stdin);
            if (strncmp(buff, "exit", 4) == 0) {
                printf("client input exit!\n");
                break;
            }
            write(sockfd, buff, strlen(buff)-1);
        }

    } else {
        while (1) {
            bzero(buff, sizeof(buff));
            ret = read(sockfd, buff, sizeof(buff));
            if (ret == 0) {
                printf("The other side had closed!\n");
                break;
            } 

            printf("%s\n", buff);
        }
    }

    close(sockfd);

    if (pd == 0) {
        kill(getppid(), SIGKILL);
    } else {
        kill(pd, SIGKILL);
    }

    return 0;   
}

server3.c

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

#define BUFF_SIZE 1024

int main(void)
{
    int server_sockfd;
    int client_sockfd;
    char ch;
    int pd;
    int ret;
    char buff[BUFF_SIZE];

    struct sockaddr_in server_addr;
    struct sockaddr_in client_addr;

    int client_addr_len;


    server_sockfd = socket(AF_INET, SOCK_STREAM, 0);

    // …Ë÷√∑˛ŒÒ∆˜µÿ÷∑
    server_addr.sin_family = AF_INET; 
    server_addr.sin_addr.s_addr = INADDR_ANY; //inet_addr("10.10.0.9");
    //server_addr.sin_port = 9734;
    server_addr.sin_port = htons(9000);

    // ∞Û∂®∏√Ã◊Ω”◊÷£¨ πµ√∏√Ã◊Ω”◊÷∫Õ∂‘”¶µƒœµÕ≥Ã◊Ω”◊÷Œƒº˛πÿ¡™∆¿¥°£
    bind(server_sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr));

    // ¥¥Ω®Ã◊Ω”◊÷∂”¡–£¨ ±£¥ÊΩ¯»Î∏√∑˛ŒÒ∆˜µƒøÕªß∂À«Î«Û°£
    listen(server_sockfd, 5);



    printf("server waiting\n");

    // µ»¥˝≤¢Ω” ’øÕªß∂À«Î«Û
    client_addr_len = sizeof(client_addr);
    //client_sockfd = accept(server_sockfd,  (struct sockaddr*)&client_addr, &client_addr_len);
          client_sockfd = accept(server_sockfd,  0, 0);

    pd = fork();
    if (pd == -1) {
        perror("create process failed!\n");
        exit(1);
    } else if (pd == 0) {
        while(1) {
            bzero(buff, sizeof(buff));
            fgets(buff, sizeof(buff), stdin);

            if (strncmp(buff, "exit", 4) == 0) {
                break;
            }

            // ◊”Ω¯≥Ã÷–£¨∑¢ÀÕ ˝æ›
            ret = write(client_sockfd, buff, strlen(buff) -1);
        }

    } else {
        while(1) {
            // ∏∏Ω¯≥Ã÷–£¨Ω” ’ ˝æ›
            bzero(buff, sizeof(buff));
            ret = read(client_sockfd, buff, sizeof(buff));
            if (ret == 0) {
                printf("The other side had closed!\n");
                break;
            } 

            printf("%s\n", buff);
        }
    }

    close(client_sockfd);
    close(server_sockfd);

    if (pd == 0) {
        kill(getppid(), SIGKILL);
    } else {
        kill(pd, SIGKILL);
    }

    return 0;   
}
posted @ 2016-04-02 11:51  夜色下的港湾  Views(232)  Comments(0Edit  收藏  举报