基于socket的简单tcp客户端与服务端程序

基于socket的简单tcp客户端与服务端程序

前一段时间,我实习所在公司的同事说想学习网络编程的知识,我向他介绍了我学习网络编程的历程,在此给大家分享一下,希望能给刚入门的小伙伴带来帮助。我当时学网络编程时,没有志同道合的小伙伴,没有专业的导师教导,自己在这个过程中摸索前行,其中的困难只有自己清楚。

自己的学习历程:

1,window网络编程带我入门,发现自己写的程序竟然可以在网络上通讯,当时感觉很神奇,由此激发我学习网络编程的兴趣。
2,渐渐的发现window网络编程的API满足不了我的需求,然后就转到Linux/Unix网络编程。
3,在实验室所谓的项目组(就我一个人)首次接触到了epoll。

在Linux下学习Linux/Unix网络编程,我的学习过程是按照下面的模式循序渐进的:

  • 1个服务端对应1个客户端
  • 1个服务端对应n个客户端

    分别使用select,poll,epoll实现1个服务端对应n个客户端。
    分析select,poll,epoll三者有何不同?
    

下面给大家分享一个基于socket的简单tcp客户端与服务端程序,
回头有时间再分享一个http下载服务器程序到github。

makefile

all:
    rm -rf server
    rm -rf client
    gcc -Wall -g server.c -o server
    gcc -Wall -g client.c -o client

服务端程序

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>
#include <stdlib.h>

#define BUFFSIZE   20480
#define BACKLOG    100

int main(int argc, char **argv)
{
    int flag;
    int clientfd;
    int listenfd = 0;
    int reuse = 1;
    int addrlen;

    char buff[BUFFSIZE];
    struct sockaddr_in addr;
    struct sockaddr_in cliaddr;
    addrlen = sizeof(struct sockaddr_in);

    if (argc < 2)
    {
        printf("Usage: %s ip port\n", argv[0]);
        goto end;
    }

    memset(&addr, 0, addrlen);
    addr.sin_family = AF_INET;
    addr.sin_port = htons(atoi(argv[2]));
    addr.sin_addr.s_addr = inet_addr(argv[1]);

    listenfd = socket(AF_INET, SOCK_STREAM, 0);
    if (listenfd == -1)
    {
        printf("fail in socket(), errno : %d, %s\n", errno, strerror(errno));
        goto end;
    }

    if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) == -1)
    {
        printf("fail in setsockopt(), errno : %d, %s\n", errno, strerror(errno));
        goto end;
    }

    if ((bind(listenfd, (const struct sockaddr *)&addr, addrlen)) == -1)
    {
        printf("fail in bind(), errno : %d, %s\n", errno, strerror(errno));
        goto end;
    }

    if (listen(listenfd, BACKLOG) == -1)
    {
        printf("fail in listen(), errno : %d, %s\n", errno, strerror(errno));
        goto end;
    }

    while (1)
    {
        printf("waiting client connect...\n");

        memset(&cliaddr, 0, addrlen);

        clientfd = accept(listenfd, (struct sockaddr *)&cliaddr, (socklen_t *)&addrlen);
        if (clientfd == -1)
        {
            printf("fail in accept(), errno : %d, %s\n", errno, strerror(errno));
            continue;
        }

        printf("new client from %s:%d\n", inet_ntoa(cliaddr.sin_addr), ntohs(cliaddr.sin_port));

        while (1)
        {
            memset(buff, 0, sizeof(buff));

            flag = recv(clientfd, buff, BUFFSIZE - 1, 0);
            if (flag == 0)
            {
                printf("peer shutdown\n");
                break;
            }
            else if (flag == -1)
            {
                if (errno == EAGAIN)
                    continue;
                else
                {
                    printf("fail in recv()\n");
                    break;
                }
            }

            printf("\nrecv data: %s\n", buff);

            if (send(clientfd, buff, strlen(buff) + 1, 0) == -1)
                break;
        }

        close(clientfd);
    }

end:
    if (listenfd)
        close(listenfd);

    return 0;
}

客户端程序

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>

#define MAX_BUFF_SIZE   1024

int main(int argc, char **argv)
{
    int flag;
    int clientfd;
    int reuse = 1;
    int addrlen;
    char buff[MAX_BUFF_SIZE];
    struct sockaddr_in addr;
    addrlen = sizeof(struct sockaddr_in);

    if (argc < 2)
    {
        printf("Usage: %s ip port\n", argv[0]);
        goto end;
    }

    memset(&addr, 0, addrlen);
    addr.sin_family = AF_INET;
    addr.sin_port = htons(atoi(argv[2]));
    addr.sin_addr.s_addr = inet_addr(argv[1]);

    clientfd = socket(AF_INET, SOCK_STREAM, 0);
    if (clientfd == -1)
    {
        printf("fail in socket(), errno : %d, %s\n", errno, strerror(errno));
        goto end;
    }

    if (setsockopt(clientfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) == -1)
    {
        printf("fail in setsockopt(), errno : %d, %s\n", errno, strerror(errno));
        goto end;
    }

    if (connect(clientfd, (const struct sockaddr *)&addr, addrlen) == -1)
    {
        printf("fail in connect(), errno : %d, %s\n", errno, strerror(errno));
        goto end;
    }

    while (1)
    {
        printf("\nplease input data:\n");
        memset(&buff, 0, sizeof(buff));
        fflush(stdin);
        scanf("%s", buff);

        printf("send date ...\n");
        if (send(clientfd, buff, strlen(buff), 0) == -1)
        {
            printf("fail in send(), errno : %d, %s\n", errno, strerror(errno));
            goto end;
        }

        printf("reve data ...\n");
        memset(buff, 0, sizeof(buff));
        flag = recv(clientfd, buff, sizeof(buff) - 1, 0);
        if (flag == -1)
        {
            printf("fail in recv()\n");
            goto end;
        }
        else if (flag == 0)
        {
            printf("peer shutdown\n");
            goto end;
        }
        else
        {
            printf("recv data:\n%s\n", buff);
        }
    }

end:
    if (clientfd)
        close(clientfd);

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值