Socket网络程序设计(1) ———— 基于TCP协议的客户-服务器socket实例

Socket网络程序设计(1)

———— 基于TCP协议的客户-服务器socket实例

1、TCP网络编程架构

这里写图片描述

2、代码段

  • 服务器:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#define PORT 8888                       /*侦听端口地址*/
#define BACKLOG 2                       /*侦听队列长度*/

int main(int argc, char *argv[])
{
    int ss,sc;      /*ss为服务器的socket描述符,sc为客户端的socket描述符*/
    struct sockaddr_in server_addr; /*服务器地址结构*/
    struct sockaddr_in client_addr; /*客户端地址结构*/
    int err;                            /*返回值*/
    pid_t pid;  
    char words[1024];   /*分叉的进行ID*/

    /*建立一个流式套接字*/
    ss = socket(AF_INET, SOCK_STREAM, 0);
    if(ss < 0){                         /*出错*/
        printf("socket error\n");
        return -1;  
    }

    /*设置服务器地址*/
    bzero(&server_addr, sizeof(server_addr));           /*清零*/
    server_addr.sin_family = AF_INET;                   /*协议族*/
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);    /*本地地址*/
    server_addr.sin_port = htons(PORT);             /*服务器端口*/

    /*绑定地址结构到套接字描述符*/
    err = bind(ss, (struct sockaddr*)&server_addr, sizeof(server_addr));
    if(err < 0){/*出错*/
        printf("bind error\n");
        return -1;  
    }

    /*设置侦听*/
    err = listen(ss, BACKLOG);
    if(err < 0){                                        /*出错*/
        printf("listen error\n");
        return -1;  
    }

        /*主循环过程*/
    for(;;) {
        socklen_t addrlen = sizeof(struct sockaddr);

        sc = accept(ss, (struct sockaddr*)&client_addr, &addrlen); 
        /*接收客户端连接*/
        if(sc < 0){                         /*出错*/
            continue;                       /*结束本次循环*/
        }else{
            sprintf(words, "%d login\n", sc);
            write(1, words, strlen(words)+1);
        }

        /*建立一个新的进程处理到来的连接*/
        pid = fork();                       /*分叉进程*/
        if( pid == 0 ){                     /*子进程中*/
            //process_conn_server(sc);      /*处理连接*/
            ssize_t size = 0;
            char buffer[1024];                          /*数据的缓冲区*/
            for(;;){                                    /*循环处理过程*/      
                size = read(sc, buffer, 1024);          /*从套接字中读取数据放到                                                   缓冲区buffer中*/
                if(size == 0){                          /*没有数据*/
                    return; 
                }
                write(1, buffer, size);                 /*写到标准输出*/
                sprintf(buffer, "From %d\n", sc);
                write(1, buffer, strlen(buffer)+1);                 /*写到标准输出*/


                /*构建响应字符,为接收到客户端字节的数量*/
                sprintf(buffer, "I receive %d bytes altogether\n", size);
                write(sc, buffer, strlen(buffer)+1);/*发给客户端*/
            }   

            close(ss);                      /*在子进程中关闭服务器的侦听*/
        }else{
            //close(sc);                        /*在父进程中关闭客户端的连接*/
        }
    }
}
  • 客户端:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <arpa/inet.h>
#define PORT 8888                               /*侦听端口地址*/
#define IP "127.0.0.1"                              /*服务器IP地址*/

int main(int argc, char *argv[])
{
    int s;                                      /*s为socket描述符*/
    struct sockaddr_in server_addr;         /*服务器地址结构*/

    s = socket(AF_INET, SOCK_STREAM, 0);        /*建立一个流式套接字 */
    if(s < 0){                                  /*出错*/
        printf("socket error\n");
        return -1;
    }

    /*设置服务器地址*/
    bzero(&server_addr, sizeof(server_addr));   /*清零*/
    server_addr.sin_family = AF_INET;                   /*协议族*/
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);    /*本地地址*/
    server_addr.sin_port = htons(PORT);             /*服务器端口*/

    /*将用户输入的字符串类型的IP地址转为整型*/
    inet_pton(AF_INET, IP, &server_addr.sin_addr);
    /*连接服务器*/
    connect(s, (struct sockaddr*)&server_addr, sizeof(struct sockaddr));
    //process_conn_client(s);                       /*客户端处理过程*/


    ssize_t size = 0;
    char buffer[1024];                          /*数据的缓冲区*/

    for(;;){                                    /*循环处理过程*/
        /*从标准输入中读取数据放到缓冲区buffer中*/
        size = read(0, buffer, 1024);
        if(size > 0){                           /*读到数据*/
            write(s, buffer, size);             /*发送给服务器*/
            size = read(s, buffer, 1024);       /*从服务器读取数据*/
            write(1, buffer, size);             /*写到标准输出*/
        }
    }


    close(s);                                   /*关闭连接*/
    return 0;
}
  • makefile:
all:client server clean                 #all规则,它依赖于client和server规则

client: tcp_client.o    #client规则,生成客户端可执行程序
    gcc -o client tcp_client.o
server: tcp_server.o    #server规则,生成服务器端可执行程序
    gcc -o server tcp_server.o  
clean:                              #清理规则,删除client、server和中间文件
    rm -f tcp_process tcp_client tcp_server *.o

3、效果展示

  • 服务器
    这里写图片描述
    不同客户端连接,会显示不同id登录,当发送信息时,也会显示是来自哪个客户端。

  • 客户端
    这里写图片描述
    两个客户端的连接,当发送信息时,会受到服务器的返回,显示收到的字符数

提供给大家源代码参考
https://github.com/KevinBetterQ/Network-programming/tree/master/TCP-Practice*


版权声明:本文为KevinBetterQ原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。