Linux 下使用C语言的TCP编程流程记录

一共两个部分:服务器、客户端

头文件:

#ifndef __MAKEU_NET_H__
#define __MAKEU_NET_H__

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>

#include <sys/select.h>
#include <sys/time.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>


#define SERV_PORT           5002  //端口
#define SERVER_IP_ADDR      "192.168.1.10"
#define BACKLOG             5

#define QUIT_STR            "quit"
#define SERV_RESP_STR       "SERVER:"



#endif

服务器:

首先介绍流程

1、socket返回一个fd

2、填写struct sockaddr_in sin 信息

3、bind绑定信息

4、listen 将fd设置为监听模式

5、accept等待客户端连接

6、用frok创建一个线程去处理这个客户端

#include "net.h"
#include "string.h"
#include "pthread.h"
#include <signal.h>
#include <sys/types.h> 
#include <sys/wait.h> 
#include <sys/socket.h>
void client_handle(void *arg);


void sig_chil_handle(int signo)
{
    if(SIGCHLD == signo)
    {
        waitpid(-1,NULL,WNOHANG);
    }
}

int main(void)
{
    int fd = -1;
    struct sockaddr_in sin;

    fd = socket(AF_INET,SOCK_STREAM,0);

    int b_reuse = 1;
    setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &b_reuse, sizeof (int));
    //填充sin数据
    sin.sin_family = AF_INET;
    sin.sin_port = htons(SERV_PORT);
    sin.sin_addr.s_addr = inet_addr(SERVER_IP_ADDR);

    if(bind(fd,(struct sockaddr *)&sin,sizeof(sin)) < 0 )
    {
        perror("bind");
        exit(1);
    }

    if(listen(fd,BACKLOG) != 0)
    {
        perror("listen");
        exit(1);
    }

    printf("server starting...OK!\n");
    int newfd;
    char buf[BUFSIZ];
    struct sockaddr_in cin;
    socklen_t addrlen = sizeof(cin);

    while (1)
    {
        pid_t pid = -1;

        if((newfd = accept(fd,(struct sockaddr *)&cin,&addrlen)) < 0)
        {
            perror("accept");
            break;
        }

        if((pid = fork()) < 0)
        {
            perror("fork");
            break;
        } 

        if(pid == 0)//子进程
        {
            close(fd);
            
            if(!inet_ntop(AF_INET,(void *)&cin.sin_addr.s_addr,buf,sizeof(cin)))
            {
                perror("inet_ntop");
                exit(1);
            }
            printf("hello\n");
            client_handle((void *)&newfd);
            return 0;
        }
        else
        {
            close(newfd);
        }
    }
}


void client_handle(void *arg)
{
    int ret = -1;
    int newfd = *(int *)arg;
    char buf[BUFSIZ];
    char resp_buf[BUFSIZ + 10];

    printf("child handling proccess : newfd = %d\n",newfd);

    while (1)
    {
        bzero(buf,BUFSIZ);
        bzero(resp_buf,BUFSIZ + 10);
        do
        {
            ret = read(newfd,buf,BUFSIZ);
        }while(ret < 0 && EINTR == errno);

        if(ret < 0)
        {
            perror("read");
            exit(1);
        }

        if(ret == 0)
        {
            printf("客户端已下线");
            break;
        }


        bzero(resp_buf,BUFSIZ+10);
        strncpy(resp_buf,SERV_RESP_STR,strlen(SERV_RESP_STR));
        strcat(resp_buf,buf);
        do
        {
            ret = write(newfd,resp_buf,strlen(resp_buf));
        }while(ret < 0 && EINTR == errno);

        printf("client (fd = %d) :%s\n",newfd,buf);
        if(!strncasecmp(buf,QUIT_STR,strlen(QUIT_STR)))
        {
            printf("Client(fd=%d) is exiting!\n",newfd);
            break;
        }
    }
    close(newfd);
    
}

客户端:

1、socket

2、填cin信息

3、connect服务器

4、用select监控键盘输入和服务器数据

#include "net.h"




int main(int argc,char **argv)
{
    struct sockaddr_in cli;
    bzero(&cli,sizeof(cli));

    int fd = socket(AF_INET,SOCK_STREAM,0);

    cli.sin_family = AF_INET;
    cli.sin_port = htons(SERV_PORT);//端口转换
    cli.sin_addr.s_addr = inet_addr(argv[1]);//要连接的地址


    if(connect(fd,(struct sockaddr *)&cli,sizeof(cli)) < 0)
    {
        perror("connect");
        exit(1);

    }//连接

    printf("cli connect succeed...OK\n");

    int maxfd = -1;
    struct timeval tout;
    fd_set rset;
    char buf[BUFSIZ];
    int ret = -1;
    int recordfd = -1;
    recordfd = open("record.txt",O_RDWR);
    while (1)
    {
        //
        FD_ZERO(&rset);
        FD_SET(0,&rset);
        FD_SET(fd,&rset);
        maxfd = fd;
        tout.tv_sec = 5;
        tout.tv_usec = 0;
        select(maxfd + 1,&rset,NULL,NULL,&tout);

        //判断哪个fd进来数据
        if(FD_ISSET(0,&rset))
        {
            bzero(buf,BUFSIZ);
            do{
                ret = read(0,buf,BUFSIZ -1);
            }while(ret < 0 && EINTR == errno);

            if(ret < 0)
            {
                perror("read");
                continue;
            }

            if(!ret)
            {
                continue;
            }

            if(write(fd , buf, strlen(buf)) < 0)
            {
                perror("write() to socket");
                continue;
            }
            if(!strncasecmp(buf,QUIT_STR,strlen(QUIT_STR)))//退出
            {
                printf("Client is exiting!\n");
                break;
            }
        }
        if(FD_ISSET(fd,&rset))
        {
            bzero(buf,BUFSIZ);
            do
            {
                ret = read(fd,buf,BUFSIZ -1);
            } while (ret < 0 && EINTR == errno);
            if(ret < 0)
            {
                perror("read");
                continue;
            }
            if(!ret)//服务器已关闭
            {
                break;
            }
            printf("server said : %s\n",buf);
            if(write(recordfd,buf,strlen(buf)) < 0)
            {
                perror("write to record\n");

            }
        }

        if(strlen(buf) > strlen(SERV_RESP_STR) && !strncasecmp(buf+strlen(SERV_RESP_STR),QUIT_STR,strlen(QUIT_STR)))
        {
            printf("client quit!\n");
            break;
        } 

    }
    close(fd);
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值