socket API和TCP/IP协议学习

socket API和TCP/IP协议学习


  • 本博客用于记录socket API和TCP/IP协议的学习
  • 目标在2017.1.1之前看完unix网络编程卷一和TCP/IP详解卷一
  • 本博客的环境是opensuse Tumbleweed,其他linux发行版可能会有差异

首先放上简单的server/client代码

这两段代码展示了socket连接的一般步骤

  • 注意:这个代码缺少了相关的头文件,不能直接跑哦!
  • 博客对应完整代码见我的github

server.c

#include <stdio.h>
#include <netinet/in.h>
#include <string.h>
#include <time.h>
#include <zconf.h>
#include <stdlib.h>
#include "../unp_prac.h"
/**
 * 这是server端的程序,流程总结为:
 * 1.函数socket返回listenfd
 * 2.设置servaddr(先使用bzero);
 * 3.bind,绑定seraddr和listenfd
 * 4.listen,将套接字转换成监听套接字。
 * ---以上socket bind listen 是任何TCP服务器准备监听描述符的正常步骤
 * 5.无穷循环for(;;)
 * 6.调用accept(等待某个连接到达并被内核接受),
 *      在accept中,TCP连接使用所谓的三路握手建立连接,完毕则返回已连接描述符(confd),用于与客户进程通信。
 * 7.关闭confd,终止连接。
 */

/**
 * 编译:
 * gcc -o server server.c ../lib_io/writen.c ../lib/error.c
 */

int main(int argc, char **argv) {
    int listenfd, confd;
    struct sockaddr_in servaddr;
    char buff[MAXLINE];
    time_t ticks;


    //socket函数创建一个网际(AF_INET)字节流(SOCK_STREAM)套接字,这是TCP套接字的花哨名字。
    //返回一个小整数的描述符。
    if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        printf("调用socket函数失败");
    }

    //设置服务器
    //将servaddr内存区域清0;
    bzero(&servaddr, sizeof servaddr);

    //设置seraddr
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);//设为any:如果服务器有多个网络接口,那么服务器进程可以在所有接口上接受用户连接
    servaddr.sin_port = htons(port);/*时间服务的端口为13*/

    //bind
    if ((bind(listenfd, (SA *) &servaddr, sizeof(servaddr))) < 0) {
        printf("\033[31mbind失败,端口未被系统释放\n请修改unp_prac.h中的port,然后clean,重新编译运行\n\033[0m");
        exit(0);
    };

    //listen
    listen(listenfd, LISTENQ);
    printf("创建监听连接符,等待连接\n");
    while (1) {

        confd = accept(listenfd, (SA *) NULL, NULL);
        printf("接受连接,返回时间\n");
        ticks = time(NULL);
        snprintf(buff, sizeof(buff), "\033[35m%.24s\n\033[0m", ctime(&ticks));
        Writen(confd, buff, strlen(buff));

        close(confd);
    }
    return 0;
}

client.c

#include <netinet/in.h>
#include <stdio.h>
#include <string.h>
#include <zconf.h>
#include "../unp_prac.h"
#include "../lib/inet_pton.h"




/**
 * 这是客户端的代码,步骤为下
 * 1.socket返回socket描述符
 * 2.设置seraddr
 * 3.connect
 * 4.read socket描述符
 */

/**
 * 编译
 * gcc -o client client.c ../lib_io/readn.c ../lib/error.c 
 */

int main(int argc, char **argv) {
    int sockfd, n;
    char recvline[MAXLINE + 1];
    struct sockaddr_in servaddr;
    char *servIP;

    if (argc != 2) {
        servIP = "127.0.0.1";
    } else {
        servIP = argv[0];
    }

    //socket函数创建一个网ji(AF_INET)字节流(SOCK_STREAM)套接字,这是TCP套接字的花哨名字。
    //返回一个小整数的描述符。
    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        printf("调用socket函数失败");
    }


    //首先清空servaddr结构体,作用等同于memset
    //书上推荐使用bzero是因为只有两个参数,比较好记
    bzero(&servaddr, sizeof servaddr);
    servaddr.sin_family = AF_INET;//置地址族为AF_INET
    servaddr.sin_port = htons(port);//htons函数负责将整数转换成二进制端口号
    if ((inet_pton(AF_INET, servIP, &servaddr.sin_addr)) < 0) {
        printf("转换失败");
    }//将ASCII命令行参数转化为正确的形式

    if (connect(sockfd, (SA *) &servaddr, sizeof(servaddr)) < 0) {
        printf("连接失败\n");
    };

    while ((n = Readn(sockfd, recvline, MAXLINE)) > 0) {
        recvline[n] = 0;
        if (fputs(recvline, stdout) == EOF) {
            printf("写到标准输出失败\n");
        }
    }
    if (n < 0) {
        printf("读取失败\n");
    }
}

相关文章

1.套接字编程基础
2.基本套接字函数

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值