Berkeley套接字

 网址:Berkeley套接字 

服务器:

#include <stdio.h>

#include <string.h>

#include <stdlib.h>

#include <unistd.h>

#include <arpa/inet.h>

#include <netinet/in.h>

#include <sys/socket.h>

#define BUF_SIZE 1024

#include <netdb.h>    //DNS头文件


(1)

void  text1()

{

    //创建套接字是 使用IPv4地址类型  SOCK_STREAM 表示面向连接的数据传输方式 么满足这两个条件的协议只有 TCP

    int serv_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    //将套接字和IP、端口绑定

    struct sockaddr_in serv_addr;

    memset(&serv_addr, 0, sizeof(serv_addr));  //每个字节都用0填充

    serv_addr.sin_family = AF_INET//使用IPv4地址

    serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");  //具体的IP地址

    //htons是将整型变量从主机字节顺序转变成网络字节顺序

    serv_addr.sin_port = htons(1234); //将端口

// sock socket 文件描述符,addr sockaddr 结构体变量的指针,addrlen addr 变量的大小,可由 sizeof() 计算得出。

//服务器端要用 bind() 函数将套接字与特定的IP地址和端口绑定起来,

    bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));

    //进入监听状态,等待用户发起请求

    listen(serv_sock, 20);//最大链接上限容量20

    //接受客户端请求

    while (1)

    {

        struct sockaddr_in clnt_addr;

        socklen_t  clnt_addr_size=sizeof(clnt_addr);

        int clnt_sock=accept(serv_sock, (struct sockaddr*)&clnt_addr, &clnt_addr_size);

        

        //向客户端发送数据

        char str[]="hall word12221";

        //写

        write(clnt_sock,str,sizeof(str));

        close(clnt_sock);

    }

    //关闭套接字

    close(serv_sock);

    

}


客户端:

#include <stdio.h>

#include <string.h>

#include <stdlib.h>

#include <unistd.h>

#include <arpa/inet.h>

#include <netinet/in.h>

#include <sys/socket.h>

#define BUF_SIZE 1024

//客户端

void  text1()

{

    

        //创建套接字是 使用IPv4地址类型  SOCK_STREAM 表示面向连接的数据传输方式 么满足这两个条件的协议只有 TCP

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

        //将套接字和IP、端口绑定

        struct sockaddr_in serv_addr;

        memset(&serv_addr, 0, sizeof(serv_addr));  //每个字节都用0填充

        serv_addr.sin_family = AF_INET//使用IPv4地址

        serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");  //具体的IP地址

      //htons是将整型变量从主机字节顺序转变成网络字节顺序

        serv_addr.sin_port = htons(1234); //将端口

    //connect() 函数用来建立连接

    connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));

    //读取服务器传回的数据

    char buffer[40];

    read(sock, buffer, sizeof(buffer)-1);

    printf("Message form server: %s\n", buffer);

    

    //关闭套接字

    close(sock);

 

    

}

运行结果:Message form server:hall word12221


(2)

//回声服务端

void test2()

{

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

    

    struct sockaddr_in sockaddr;

    memset(&sockaddr, 0, sizeof(sockaddr));

    sockaddr.sin_family = AF_INET;

    sockaddr.sin_addr.s_addr = inet_addr("127.0.0.1");

    sockaddr.sin_port = htons(1234);

    bind(serverSock, (struct sockaddr*)&sockaddr, sizeof(sockaddr));

    

    listen(serverSock, 20);

    

    //接受客户端请求

    struct sockaddr_in clnAddr;

    socklen_t nSize = sizeof(clnAddr);

    int clnSock = accept(serverSock, (struct sockaddr*)&clnAddr, &nSize);

    

    

    char buffer[100];

    ssize_t strlen = read(clnSock, buffer, sizeof(buffer)-1);//接受客户端发来的数据

    

    printf("Message from client: %s\n",buffer);

    write(clnSock, buffer, strlen);

    

    close(serverSock);

    close(clnSock);

    

    

    

}


//回声客户端

void test2()

{

    int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    

    struct sockaddr_in sockaddr;

    memset(&sockaddr, 0, sizeof(sockaddr));

    sockaddr.sin_family = AF_INET;

    sockaddr.sin_addr.s_addr = inet_addr("127.0.0.1");

    sockaddr.sin_port = htons(1234);

    

    if (connect(sock, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) == -1) {

        printf("链接失败\n");

    }

    

    //获取用户输入的字符串并发送给服务器

    char bufSend[40];

    printf("input a string: ");

    scanf("%s",bufSend);

    write(sock, bufSend, strlen(bufSend));

    

    //接受服务器传回的数据

    char bufRecev[100];

    read(sock, bufRecev, sizeof(bufRecev)-1);

    

    printf("message fromServer: %s\n",bufRecev);

    

    close(sock);

}


运行结果: input a string:(手动输入什么)

           message fromServer:(就打印什么)

(3)


服务:

//服务

//client server 下载一个文件并保存到本地。

void test4()

{

    char* filename = "/Users/mac/Desktop/Level1_1.tmx";

    FILE * fp = fopen(filename, "rb");

    if (fp == NULL) {

        printf("Cannot open file, press any key to exit!\n");

        system("pause");

        exit(0);

    }

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

    struct sockaddr_in sockaddr;

    memset(&sockaddr, 0, sizeof(sockaddr));

    sockaddr.sin_family = AF_INET;

    sockaddr.sin_addr.s_addr = inet_addr("127.0.0.1");

    sockaddr.sin_port = htons(1234);

    bind(serverSock, (struct sockaddr*)&sockaddr, sizeof(sockaddr));

    listen(serverSock, 20);

    int clnaddr;

    socklen_t nsize = sizeof(clnaddr);

    int clnSock = accept(serverSock, (struct sockaddr*)&clnaddr, &nsize);

    //循环发送数据,直到文件结尾

    char buffer[BUF_SIZE];

    size_t nCount;

    //当读取到文件末尾,fread() 会返回 0,结束循环

    int i = 0;

    while ((nCount = fread(buffer, 1, BUF_SIZE, fp)) > 0) {

        write(clnSock, buffer, nCount);

        i++;

    }

    shutdown(clnSock, SHUT_WR); //文件读取完毕,断开输出流,向客户端发送FIN

    read(clnSock, buffer, BUF_SIZE);//阻塞,等待客户端接收完毕

    fclose(fp);

    close(serverSock);

    close(clnSock);

    printf("********%d\n",i);

}


客户端:

//client server 下载一个文件并保存到本地。

void test4()

{

    char * filename = "/Users/mac/Desktop/Level18_1.tmx";

    FILE* fp = fopen(filename, "wb");

    if (fp == NULL) {

        printf("Cannot open file, press any key to exit!\n");

        system("pause");

        exit(0);

    }

    int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    struct sockaddr_in sockaddr;

    sockaddr.sin_family = AF_INET;

    sockaddr.sin_addr.s_addr = inet_addr("127.0.0.1");

    sockaddr.sin_port = htons(1234);

    if (connect(sock, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) == -1) {

        printf("链接失败!\n");

    }

    //循环接受数据,直到文件传输完毕

    char buffer[BUF_SIZE];

    size_t nCount;

    /*

     就是文件传输完毕后让 recv() 返回 0,结束 while 循环。

     注意:读取完缓冲区中的数据 recv() 并不会返回 0,而是被阻塞,直到缓冲区中再次有数据。

     */

    while ((nCount = read(sock, buffer, BUF_SIZE))>0) {

        fwrite(buffer, nCount, 1, fp);

    }

    printf("File transfer success\n");

    fclose(fp);

    close(sock);

}


运行结果:把服务器上的Level1_1.tmx,拷贝下来名为Level18_1.tmx



(4)

服务器:

//粘包问题

void test3()

{

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

    struct sockaddr_in sockaddr;

    memset(&sockaddr, 0, sizeof(sockaddr));

    sockaddr.sin_family = AF_INET;

    sockaddr.sin_addr.s_addr = inet_addr("127.0.0.1");

    sockaddr.sin_port = htons(1234);

    bind(serverSock, (struct sockaddr*)&sockaddr, sizeof(sockaddr));

    listen(serverSock, 20);

    //接受客户端请求

    struct sockaddr_in clnAddr;

    socklen_t nSize = sizeof(clnAddr);

    int clnSock = accept(serverSock, (struct sockaddr*)&clnAddr, &nSize);

    char buffer[40];

    sleep(5);//让程序暂停5

    ssize_t strlen = read(clnSock, buffer, sizeof(buffer)-1);//接受客户端发来的数据

    write(clnSock, buffer, strlen);

}


客户端


//粘包问题

void test3()

{

    int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    

    struct sockaddr_in sockaddr;

    sockaddr.sin_family = AF_INET;

    sockaddr.sin_addr.s_addr = inet_addr("127.0.0.1");

    sockaddr.sin_port = htons(1234);

    connect(sock, (struct sockaddr*)&sockaddr, sizeof(sockaddr));

    //获取用户输入的字符串并发送给服务器

    char bufSend[40];

    for (int i = 0; i < 3; i++) {

        printf("input a string: ");

        scanf("%s",bufSend);

        write(sock, bufSend, strlen(bufSend));

    }

    //接受服务器传回的数据

    char bufRecev[50];

    read(sock, bufRecev, sizeof(bufRecev)-1);

    printf("\nmessage from server:%s\n",bufRecev);

    close(sock);

    

}

运行结果:input a string: 2(手动输入什么)

input a string: 3

input a string: 4

nmessage from server:234

client 的 send() 发送了三个数据包,而 server 的 recv() 却只接收到一个数据包,这很好的说明了数据的粘包问题。


(5)

通过域名获取IP地址

服务端:

//DNS

void test5()

{

    struct hostent *host = gethostbyname("www.baidu.com");

    if (!host) {

        puts("Get IP address error!");

        system("pause");

        exit(0);

    }

    

    //别名

    for (int i = 0; host->h_aliases[i]; i++) {

        printf("Aliases %d: %s\n", i+1, host->h_aliases[i]);

    }

    //地址类型

    printf("Address type: %s\n", (host->h_addrtype==AF_INET) ? "AF_INET": "AF_INET6");

    //IP地址

    for(int i=0; host->h_addr_list[i]; i++){

        printf("IP addr %d: %s\n", i+1, inet_ntoa( *(struct in_addr*)host->h_addr_list[i] ) );

    }

    

}


运行结果:

Aliases 1: www.baidu.cn

Address type: AF_INET

IP addr 1: 111.13.100.92

IP addr 2: 111.13.100.91



(6)

TCP 是面向连接的传输协议,建立连接时要经过三次握手,断开连接时要经过四次握手,中间传输数据时也要回复ACK包确认,多种机制保证了数据能够正确到达,不会丢失或出错。
UDP 是非连接的传输协议,没有建立连接和断开连接的过程,它只是简单地把数据丢到网络中,也不需要ACK包确认。
UDP 传输数据就好像我们邮寄包裹,邮寄前需要填好寄件人和收件人地址,之后送到快递公司即可,但包裹是否正确送达、是否损坏我们无法得知,也无法保证。UDP 协议也是如此,它只管把数据包发送到网络,然后就不管了,如果数据丢失或损坏,发送端是无法知道的,当然也不会重发

服务器

void UDPtest(){

    int sock = socket(AF_INET, SOCK_DGRAM, 0);

    struct sockaddr_in seraddr;

    memset(&seraddr, 0, sizeof(seraddr));

    seraddr.sin_family = AF_INET;

    //    seraddr.sin_addr.s_addr = htonl(INADDR_ANY); //自动获取IP地址

    seraddr.sin_addr.s_addr = inet_addr("127.0.0.1");

    seraddr.sin_port = htons(1234);

    bind(sock, (struct sockaddr*)&seraddr, sizeof(seraddr));

    //接受客户端请求

    struct sockaddr_in clnaddr;

    socklen_t nsize = sizeof(clnaddr);

    /*

     由于UDP数据的发送端不定,所以 recvfrom() 函数定义为可接收发送端信息的形式,具体参数如下:

     sock:用于接收UDP数据的套接字;

     buf:保存接收数据的缓冲区地址;

     nbytes:可接收的最大字节数(不能超过buf缓冲区的大小);

     flags:可选项参数,若没有可传递0

     from:存有发送端地址信息的sockaddr结构体变量的地址;

     addrlen:保存参数 from 的结构体变量长度的变量地址值。

     */

    /*

     LinuxWindows下的 sendto() 函数类似,下面是详细参数说明:

     sock:用于传输UDP数据的套接字;

     buf:保存待传输数据的缓冲区地址;

     nbytes:带传输数据的长度(以字节计);

     flags:可选项参数,若没有可传递0

     to:存有目标地址信息的 sockaddr 结构体变量的地址;

     addrlen:传递给参数 to 的地址值结构体变量的长度

     */

    while (1) {

        char buffer[BUF_SIZE];

        ssize_t strlen = recvfrom(sock, buffer, BUF_SIZE, 0, (struct sockaddr*)&clnaddr, &nsize);

        printf("Message form client: %s\n", buffer);

        sendto(sock, buffer, strlen, 0, (struct sockaddr*) &clnaddr, nsize);

    }

    close(sock);

    

}

客户端

void UDPtest(){

    

    int sock = socket(AF_INET, SOCK_DGRAM , 0);

    

    //服务器地址信息

    struct sockaddr_in sockadr;

    sockadr.sin_family = AF_INET;

    sockadr.sin_addr.s_addr = inet_addr("127.0.0.1");

    sockadr.sin_port = htons(1234);

    

    //不断获取用户输入并发送给服务器,然后接受服务器数据

    struct sockaddr* fromAddr;

    socklen_t addrLen = sizeof(fromAddr);

    int i=1;

    while (i) {

        char buffer[BUF_SIZE] = {0};

        printf("input a string :");

        scanf("%s",buffer);

        sendto(sock, buffer, strlen(buffer), 0, (struct sockaddr*)&sockadr, sizeof(sockadr));

        

        ssize_t strlen = recvfrom(sock, buffer, BUFSIZ, 0, (struct sockaddr*)&fromAddr, &addrLen);

        buffer[strlen] = 0;

        printf("Message form server: %s\n", buffer);

    }

    close(sock);

}


运行结果:

input a string :1

Message form server: 1

input a string :2

Message form server: 2

input a string :3

Message form server: 3





  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值