Socket编程下篇-----TCP协议的C/S案例

一共有4个源码文件组成。

tcp_net_socket.h源码:

#ifndef __TCP__NET__SOCKET__H
#define __TCP__NET__SOCKET__H
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<signal.h>

extern int tcp_init(const char* ip, int port);
extern int tcp_accept(int sfd);
extern int tcp_connect(const char* ip, int port);
extern void signalhandler(void);
#endif

tcp_net_socket.c源码:

#include "tcp_net_socket.h"

//用于初始化,返回一个经过bind、listen处理以后的socket
int tcp_init(const char* ip, int port)
{
    //首先创建一个Socket,向系统申请
    int sfd = socket(AF_INET, SOCK_STREAM, 0);
    if(sfd == -1)
    {
        perror("server socket");
        exit(-1);
    }

    struct sockaddr_in serveraddr;
    memset(&serveraddr, 0, sizeof(struct sockaddr));
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_port = htons(port);
    serveraddr.sin_addr.s_addr = inet_addr(ip);

    //将新的socket与指定的ip、port绑定
    if(bind(sfd, (struct sockaddr*)&serveraddr, sizeof(struct sockaddr))==-1)
    {
        perror("bind");
        close(sfd);
        exit(-1);
    }

    //监听它,并设置其允许最大的连接数为10个
    if(listen(sfd, 10) == -1)
    {
        perror("listen");
        close(sfd);
        exit(-1);
    }
    return sfd;
}

//用于服务端的接收,返回一个经过accept处理以后的new_fd
int tcp_accept(int sfd)
{
    struct sockaddr_in clientaddr;
    memset(&clientaddr, 0, sizeof(struct sockaddr));
    int addrlen = sizeof(struct sockaddr);
    int new_fd = accept(sfd, (struct sockaddr*)&clientaddr, &addrlen);
    //sfd接受客户端连接,并创建新的socket为new_fd,将请求连接的客户端的IP、port保存在结构体clientaddr中
    if(new_fd == -1)
    {
        perror("accept");
        close(sfd);
        exit(-1);
    }
    printf("success connect......\n");
    return new_fd;
}

//用于客户端连接
int tcp_connect(const char* ip, int port)
{
    int sfd = socket(AF_INET, SOCK_STREAM, 0);
    if(sfd == -1)
    {
        perror("client socket");
        exit(-1);
    }

    struct sockaddr_in serveraddr;
    memset(&serveraddr, 0, sizeof(struct sockaddr));
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_port = htons(port);
    serveraddr.sin_addr.s_addr = inet_addr(ip);
    //将sfd连接到指定服务器网络地址serveraddr
    if(connect(sfd, (struct sockaddr*)&serveraddr, sizeof(struct sockaddr))==-1)
    {
        perror("connect");
        close(sfd);
        exit(-1);
    }
    return sfd;
}

//用于信号处理,让服务端在按下Ctrl+c或Ctrl+\时不会退出
void signalhandler(void)
{
    sigset_t sigSet;
    sigemptyset(&sigSet);
    sigaddset(&sigSet, SIGINT);
    sigaddset(&sigSet, SIGQUIT);
    sigprocmask(SIG_BLOCK, &sigSet, NULL);
}

tcp_net_server.c源码:

#include "tcp_net_socket.h"

int main(int argc, char* argv[])
{
    if(argc < 3)
    {
        printf("用法:./tcp_net_server ip port\n");
        exit(-1);
    }

    signalhandler();
    int sfd = tcp_init(argv[1], atoi(argv[2]));

    //while循环表示可以与多个客户端接收和发送,但是仍是阻塞模式
    while(1)
    {
        int connected_fd = tcp_accept(sfd);
        char buf[512] = {0};
        //从connected_fd客户端接收数据存储于buf中
        if(recv(connected_fd, buf, sizeof(buf), 0)==-1)
        {
            perror("server recv");
            close(connected_fd);
            close(sfd);
            exit(-1);
        }
        puts(buf);
        //向connected_fd客户端发送hello world数据
        if(send(connected_fd, "hello world", 12, 0) == -1)
        {
            perror("server send");
            close(connected_fd);
            close(sfd);
            exit(-1);
        }
        //每个客户端完成一次发送接收,就把客户端连接资源释放。
        close(connected_fd);
    }
    close(sfd);
    return 0;
}

tcp_net_client.c源码:

#include "tcp_net_socket.h"

int main(int argc, char* argv[])
{
    if(argc < 3)
    {
        printf("用法:./tcp_net_client ip port\n");
        exit(-1);
    }

    int sfd = tcp_connect(argv[1], atoi(argv[2]));
    char buf[512] = {0};
    send(sfd, "hello", 6, 0);
    recv(sfd, buf, sizeof(buf), 0);
    puts(buf);
    close(sfd);
}

调试程序:

//编译程序
gcc -o tcp_net_server tcp_net_server.c tcp_net_socket.c
gcc -o tcp_net_client tcp_net_client.c tcp_net_socket.c
//运行程序
./tcp_net_server 172.16.125.150 8888
./tcp_net_client 172.16.125.150 8888

此处的ip最好填写本机IP,端口号填写大于1024的整数就好。

猜你喜欢

转载自blog.csdn.net/qq_36006553/article/details/74910562