网络编程套接字(二)

简单的TCP服务器/客户端程序

server
/*================================================================

# File Name: tcp_server.c
# Author: rjm
# mail: [email protected]
# Created Time: 2018年05月06日 星期日 11时24分35秒

================================================================*/


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

#define ADDR_FAMILY AF_INET
#define PORT_NUM 8080

//定义一个结构体保存线程创建所执行函数需要的参数
typedef struct Arg
{
    int sockfd;
    struct sockaddr_in addr;
}Arg;


void* service(void* ptr)
{
    Arg* arg = (Arg*)ptr;

    char buf_ip[1024];
    //清空buf_ip
    buf_ip[0] = 0;
    //inet_ntop转换client_sock的ip
    if(inet_ntop(AF_INET, &arg->addr.sin_addr, buf_ip, sizeof(buf_ip)) == NULL)
    {
        perror("inet_ntop");
        return NULL;
    }

    while(1) 
    {
        //定义buf缓冲区
        char buf[1024];
        //清空
        buf[0] = 0;
        //从client_sock读取数据到buf
        ssize_t read_ret = read(arg->sockfd, buf, sizeof(buf));
        if(read_ret < 0)
        {
            perror("read");
            break;
        }
        if(read_ret == 0)
        {
            printf("[client %s:%d] leave! \n", buf_ip, arg->addr.sin_port);
            break;
        }
        printf("[client %s:%d] say: %s\n", buf_ip, arg->addr.sin_port, buf);

        //将buf中的数据写到client_sock
        //将消息回显给用户
        int write_ret = write(arg->sockfd, buf, sizeof(buf));
        if(write_ret < 0)
        {
            perror("write");
            break;
        }
        buf[strlen(buf)-1] = '\0';
    }
    free(arg);
    arg = NULL;
    return NULL;
}


int main(int argc, char* argv[])
{
    if(argc != 2)
    {
        printf("Usage: ./server [ip]\n");
        return -1;
    }
    //1,打开socket 得到sock
    int sock = socket(AF_INET, SOCK_STREAM, 0);//ipv4, tcp 
    if(sock < 0)
    {
        perror("socket");
        return 1;
    }

    //2,定义两个sockaddr_in结构体的对象
    struct sockaddr_in server_socket;
    struct sockaddr_in client_socket;

    //3,结构体初始化
    server_socket.sin_family = ADDR_FAMILY;
    server_socket.sin_port = htons(PORT_NUM);
    server_socket.sin_addr.s_addr = inet_addr(argv[1]);

    //4,绑定(sock和server_sock绑定)
    int bind_ret = bind(sock, (struct sockaddr*)&server_socket, sizeof(struct sockaddr_in));
    if(bind_ret < 0)
    {
        perror("bind");
        return 2;
    }

    //5,监听
    int listen_ret = listen(sock, 5);
    if(listen_ret < 0)
    {
        perror("listen");
        return 3;
    }

    //走到这说明绑定和监听成功
    printf("Wecome to Online Chat Server\n");

    //6,循环, 获得client_sock
    while(1)
    {
        socklen_t addrlen = sizeof(struct sockaddr_in);
        //获得client_sock;
        int client_sock = accept(sock, (struct sockaddr*)&client_sock, &addrlen);

        //定义buf_ip缓冲区
        char buf_ip[1024];
        //清空buf_ip
        buf_ip[0] = 0;
        //inet_ntop转换client_sock的ip
        if(inet_ntop(AF_INET, &client_socket.sin_addr, buf_ip, sizeof(buf_ip)) == NULL)
        {
            perror("inet_ntop");
            return 4;
        }
        printf("[client %s:%d] connected\n",
                    buf_ip, client_socket.sin_port);
        //7,循环服务
        /*====================================多进程版本===========================================

        int pid = fork();
        if(pid == 0)
        {
            int id = fork();
            if(id == 0)
            {
                //孙子进程
                while(1) 
                {
                    //定义buf缓冲区
                    char buf[1024];
                    //清空
                    buf[0] = 0;
                    //从client_sock读取数据到buf
                    ssize_t read_ret = read(client_sock, buf, sizeof(buf));
                    if(read_ret < 0)
                    {
                        perror("read");
                        break;
                    }
                    if(read_ret == 0)
                    {
                        printf("[client %s:%d] leave! \n", buf_ip, client_socket.sin_port);
                        break;
                    }
                    printf("[client %s:%d] say: %s\n", buf_ip, client_socket.sin_port, buf);

                    //将buf中的数据写到client_sock
                    //将消息回显给用户
                    int write_ret = write(client_sock, buf, sizeof(buf));
                    if(write_ret < 0)
                    {
                        perror("write");
                        break;
                    }
                    buf[strlen(buf)-1] = '\0';
                }

            }
        }
        */

        //====================================多线程版本===========================================

        pthread_t tid;
        Arg* arg = (Arg*)malloc(sizeof(Arg)); 
        arg->sockfd = client_sock;
        arg->addr = client_socket;
        int pthread_ret = pthread_create(&tid, NULL, service, (void*)arg);
        if(pthread_ret < 0)
        {
            perror("pthread_create");
            return 5;
        }
        pthread_detach(tid);
    }
    //8,服务完毕 关闭sock
    close(sock);
    return 0;
}
client
/*================================================================

# File Name: tcp_client.c
# Author: rjm
# mail: [email protected]
# Created Time: 2018年05月06日 星期日 11时24分19秒

================================================================*/


#include <stdio.h>
#include <sys/types.h>  
#include <sys/socket.h>
#include <arpa/inet.h>
#include <strings.h>
#include <unistd.h>
#include <string.h>

#define ADDR_FAMILY AF_INET
#define PORT_NUM 8080


int main(int argc, char* argv[])
{
    if(argc != 2)
    {
        printf("Usage: ./client [ip]\n");
        return 1;
    }
    printf("Welcome to Online Chat Client\n");
    //1, 打开socket
    int sock = socket(AF_INET, SOCK_STREAM, 0); //ipv4, tcp
    if(sock < 0)
    {
        perror("socket");
        return 2;
    }
    //2, 定义buf缓冲区 清空
    char buf[1024];
    buf[0] = 0;
    //3, 定义sockaddr_in对象server_sock
    struct sockaddr_in server_sock;
    //3, bzero() server_sock
    bzero(&server_sock, sizeof(struct sockaddr_in));

    //4, 初始化server_sock
    server_sock.sin_family = ADDR_FAMILY;
    server_sock.sin_port = htons(PORT_NUM);
    server_sock.sin_addr.s_addr = inet_addr(argv[1]);
    //5, 连接server
    int connect_ret = connect(sock, (struct sockaddr*)&server_sock, sizeof(struct sockaddr_in));
    if(connect_ret < 0)
    {
        perror("connect");
        return 3;
    }
    //6, 循环发送消息
    while(1)
    {
        printf("Please Enter: ");
        fflush(stdout);
        //fgets()到buf
        fgets(buf, sizeof(buf), stdin);
        buf[strlen(buf)-1] = 0;
        //比较quit 退出
        if(strcmp(buf, "quit") == 0)
        {
            printf("bye!\n");
            break;
        }
        //把buf中的数据写到sock
        int write_ret = write(sock, buf, sizeof(buf));
        if(write_ret < 0)
        {
            perror("write");
            return 4;
        }
        //把sock中的数据读到buf
        int read_ret = read(sock, buf, sizeof(buf));
        printf("server echo: %s\n", buf);
    }
    //7, 结束关闭sock
    close(sock);

    return 0;
}

测试效果
这里写图片描述
这里写图片描述
这里写图片描述

UDP 与 TCP 对比

  • 可靠传输 vs 不可靠传输
  • 有连接 vs 无连接
  • 字节流 vs 数据报

TCP的优点

  • 可靠,稳定
    TCP的可靠体现在TCP在
    传递数据之前,会有三次握手来建立连接,
    而且在数据传递时,有确认、窗口、重传、拥塞控制机制,
    在数据传完后,还会断开连接用来节约系统资源。

TCP的缺点

  • 慢,效率低,占用系统资源高,易被攻击 TCP在传递数据之前,要先建连接,这会消耗时间,
    而且在数据传递时,确认机制、重传机制、拥塞控制机制等都会消耗大量的时间,而且要在每台设备上维护所有的传输连接,
    事实上,每个连接都会占用系统的CPU、内存等硬件资源。
    而且,因为TCP有确认机制、三次握手机制,这些也导致TCP容易被人利用,实现DOS、DDOS、CC等攻击。

UDP的优点
快,比TCP稍安全 UDP没有TCP的握手、确认、窗口、重传、拥塞控制等机制,UDP是一个无状态的传输协议,所以它在传递数据时非常快。没有TCP的这些机制,UDP较TCP被攻击者利用的漏洞就要少一些。
但UDP也是无法避免攻击的,比如:UDP Flood攻击……

UDP的缺点
不可靠,不稳定 因为UDP没有TCP那些可靠的机制,在数据传递时,如果网络质量不好,就会很容易丢包。

什么时候应该使用TCP:

  • 当对网络通讯质量有要求的时候,比如:整个数据要准确无误的传递给对方,这往往用于一些要求可靠的应用,比如HTTP、HTTPS、FTP等传输文件的协议,POP、SMTP等邮件传输的协议。 在日常生活中,常见使用TCP协议的应用如下: 浏览器,用的HTTP FlashFXP,用的FTP Outlook,用的POP、SMTP Putty,用的Telnet、SSH QQ文件传输 …………

什么时候应该使用UDP:

  • 当对网络通讯质量要求不高的时候,要求网络通讯速度能尽量的快,这时就可以使用UDP。 比如,日常生活中,常见使用UDP协议的应用如下: QQ语音 QQ视频 TFTP ……
    有些应用场景对可靠性要求不高会用到UPD,比如长视频,要求要有一定的速率

猜你喜欢

转载自blog.csdn.net/sinat_36629696/article/details/80356124