Linux Socket网络编程 分别使用TCP协议 和 UDP协议

网络模型:

这里写图片描述

Socket编程模型:

这里写图片描述

Socket的实质就是一个接口, 利用该接口,用户在使用不同的网络协议时,操作函数得以统一。而针对不同协议的差异性操作,则交给了socket去自行解决。

创建Socket套接字

函数原形:
int socket(int domain, int type, int protocol);

函数功能: 创建socket套接字

所属头文件:

#include <sys/types.h>
#include <sys/socket.h>

返回值:
若成功,返回套接字的标识符;若失败,返回-1.

参数说明:
domain:指明了网络域,AF_INET,用于ipv4;AF_INET6,用于ipv6。
type:协议类型,SOCK_STREAM

上面两个参数填写如下:
如:UDP协议就是AF_INET 和 SOCK_DGRAM
如:TCP协议就是AF_INET 和 SOCK_STREAM

protocol: UDP协议和TCP协议这里可以为0.

绑定地址

函数原形:
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

函数功能: 为套接字绑定相应的IP地址

所属头文件:

#include <sys/types.h>
#include <sys/socket.h>

返回值:
若成功,返回0;若失败,返回-1.

参数说明:
sockfd:指定的socket套接字的ID
*addr:要绑定的地址,这是bind函数用到的地址类型,通用类型,第一个成员,协议族的类型,第二个成员,具体的协议值
这里写图片描述
addrlen:地址的长度,addr指向内容的长度

注意:
上述地址结构体由于不方便赋值,因此在编程中不采用,使用下面的结构体:

struct sockaddr_in 
{
    short int sin_family;
    unsigned short int sin_port;//2字节
    struct in_addr sin_addr;//4字节
    unsigned char sin_zero[8];//8字节
};
struct in_addr
{
    unsigned long s_addr;//此处为整形的IP地址
};

两种结构中地址数据都为 14Bytes,该结构体专用于IPV4,且需要加上头文件:

#include <netinet/in.h>

设置监听端口

函数原形:
int listen(int sockfd, int backlog);

函数功能: 监听网络端口

所属头文件:

#include <sys/types.h>
#include <sys/socket.h>

返回值:
若成功,返回0;若失败,返回-1.

参数说明:
sockfd:指定监听其他端口的socket标识符ID(它去监听别人)
backlog:客户机的数目,允许多少个连接

等待连接函数

函数原形:
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

函数功能:
等待客户机连接,若无连接,服务器阻塞,有链接,继续运行

所属头文件:

#include <sys/types.h>
#include <sys/socket.h>

返回值:
若成功,返回连接到的套接字的标识符;若失败,返回-1.

参数说明:
sockfd:正在监听的socket标识符,这是原始套接字ID,函数返回的是一个新的套接字ID,新ID连接到客户机,接收客户机传来的数据用新ID,原始ID可以接收其他连接请求。
*addr:客户机的地址
*addrlen:客户机的地址的长度,特别注意这里地址长度为指针

发送数据

函数原形:
ssize_t send(int sockfd, const void *buf, size_t len, int flags);

函数功能: 从套接字上发送数据

所属头文件:

#include <sys/types.h>
#include <sys/socket.h>

返回值:
若成功,返回发送的字节数;若失败,返回-1.

参数说明:
sockfd:发送数据的套接字ID,就是数据来源方的socket套接字的ID
*buf:发送数据存在的位置
len:发送数据的长度
flags:标志,可以直接设为0

接收数据

函数原形:
ssize_t recv(int sockfd, void *buf, size_t len, int flags);

函数功能:
从一个socket套接字接收数据

所属头文件:

#include <sys/types.h>
#include <sys/socket.h>

返回值:
若成功,返回接收到的字节数目;若失败,返回-1.

参数说明:
sockfd:连接成功后accept函数产生的新的套接字ID,数据来源方的ID。
*buf:接收数据存放的位置
len:接收数据的长度
flags:标志

关闭连接

close 与关闭文件函数相同用法

连接服务器

函数原形:
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

函数功能: 工作在客户机上,连接服务器

所属头文件:

#include <sys/types.h>
#include <sys/socket.h>

返回值:
若成功,返回0;若失败,返回-1.

参数说明:
sockfd:客户机的套接字
*addr:服务器的地址
addrlen:服务器的地址的长度

UDP发送数据

函数原形:
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);

函数功能:
从套接字上发送数据,用于UDP协议中

所属头文件:

#include <sys/types.h>
#include <sys/socket.h>

返回值:
若成功,返回发送的字节数;若失败,返回-1.

参数说明:
sockfd:发送数据的套接字ID描述符
*buf:发送数据存在的位置
len:发送数据的长度
flags:标志,可以直接设为0
*dest_addr:目的IP地址
addrlen:目的地址长度

UDP接收数据

函数原形:
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);

函数功能:
从一个socket套接字接收数据,用于UDP协议

所属头文件:

#include <sys/types.h>
#include <sys/socket.h>

返回值:
若成功,返回接收到的字节数目;若失败,返回-1.

参数说明:
sockfd:连接成功后accept函数产生的新的套接字ID
*buf:接收数据存放的位置
len:希望接收数据的长度
flags:标志
*src_addr:保存数据的来源方的IP地址
*addrlen:保存来源地址的长度,注意这里是指针

TCP协议编程模型:

这里写图片描述

通信之前首先要连接,没连接就等待。

这里写图片描述

UDP协议编程模型:

这里写图片描述

若服务器没有接收到数据,就一直等待。

这里写图片描述

IP地址格式的转换:

in_addr_t inet_addr(const char *cp)
功能:将字符串形式的IP地址转化为整数型的IP地址,整形的地址已经是网络字节序
范例: in_addr.saddr = inet_addr(“192.168.1.1”);

char *inet_ntoa (struct in_addr)
功能:将整数形式的IP地址转化为字符串形式的IP地址

网络字节序的转换:

网络通信中数据的发送和接收统一规定为大端模式,即:高位数据存放在低位地址处。因此只要数据大于等于2字节,都要进行如下转换:
- 发端: 从本机字节序转换为网络字节序
- 收端: 从网络字节序转换为本机字节序

uint32_t htonl(uint32_t hostlong);
将32位的数据从主机字节序转换为网络字节序
in_addr.saddr = htonl(INADDR_ANY);
//绑定所有的IP地址

uint16_t htons(uint16_t hostshort);
将16位的数据从主机字节序转换为网络字节序

uint32_t ntohl(uint32_t netlong);
将32位的数据从网络字节序转换为主机字节序

uint16_t ntohs(uint16_t netshort);
将16位的数据从网络字节序转换为主机字节序

例程:

1、TCP服务器,采用多进程实现并发。

/* 实现并发处理服务器,使用多进程 */
/* TCP协议中服务器的程序 */
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <netinet/in.h>
#include <stdlib.h>

#define portnum 3333

void main()
{
    int pid;//进程ID 
    int socket_server1;//服务器套接字标识符
    int socket_server2;//服务器连接之后的套接字标识符
    struct sockaddr_in server_addr;//服务器地址,使用的是IPV4地址结构
    struct sockaddr_in client_addr;//客户机地址,使用的是IPV4地址结构
    int size_addr;
    char receive_buffer[128];//接收到的数据存放的位置
    int receive_nbytes;//接收到的字节数目

    //创建socket  套接字
    socket_server1 = socket(AF_INET, SOCK_STREAM, 0);
    if (socket_server1 == -1)//失败就退出
    {
        printf("creat socket of server fail.\n");
        exit(1);
    }

    //设置要绑定的服务器地址
    bzero(&server_addr, sizeof(struct sockaddr_in));//清零
    server_addr.sin_family = AF_INET;//协议族
    server_addr.sin_port = htons(portnum);//端口号,且 转换为网络字节序
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    //绑定所有的IP地址,转换为网络字节序

    //绑定地址  
    bind(socket_server1, (struct sockaddr *) (&server_addr),
     sizeof(struct sockaddr));

    //监听端口
    listen(socket_server1, 5);

    size_addr = sizeof(struct sockaddr);
    while(1)
    {
        //等待连接
        socket_server2 = accept(socket_server1,
         (struct sockaddr *) (&client_addr),
         (socklen_t *) (&size_addr));       
        //特别注意这里地址长度为指针 
        printf("server get connection from %s\n",
         inet_ntoa(client_addr.sin_addr));

        //一旦实现了连接,就创建一个子进程
        pid = fork();
        if (pid == 0)
        {
            //接收客户机数据
            receive_nbytes = recv(socket_server2, receive_buffer, 128, 0);
            receive_buffer[receive_nbytes] = '\0';//添加结束符
            printf("server received %s\n", receive_buffer);

            close(pid);
            //结束新建立的连接
            close(socket_server2);
            exit(0);
        }
    }           
    //结束原始的连接
    close(socket_server1);
}

2、TCP客户端

/* TCP协议中客户机的程序 */
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <netinet/in.h>
#include <stdlib.h>

#define portnum 3333

void main()
{
    int socket_client;//服务器套接字标识符
    struct sockaddr_in server_addr;//服务器地址,使用的是IPV4地址结构
    struct sockaddr_in client_addr;//客户机地址,使用的是IPV4地址结构
    int connect_tmp;//判断连接是否成功
    char buffer[128];//发送的数据存放的位置
    int nbytes;//发送的字节数目

    //创建socket  套接字
    socket_client = socket(AF_INET, SOCK_STREAM, 0);
    if (socket_client == -1)//失败就退出
    {
        printf("creat socket of client fail.\n");
        exit(1);
    }

    //设置要连接的服务器地址
    bzero(&server_addr, sizeof(struct sockaddr_in));//清零
    server_addr.sin_family = AF_INET;//协议族
    server_addr.sin_port = htons(portnum);//端口号,且 转换为网络字节序
    server_addr.sin_addr.s_addr = inet_addr("192.168.234.129");
    //指定IP地址,转换为整数类型的地址,已经是网络字节序

    //连接服务器
    connect(socket_client, (struct sockaddr *)(&server_addr),
     sizeof(struct sockaddr));
    if (connect_tmp == -1)
    {
        printf("connect fail.\n");
        exit(1);
    }

    //发送数据
    printf("Please input char.\n");
    fgets(buffer, 128, stdin);
    send(socket_client, buffer, strlen(buffer), 0);

    //结束连接
    close(socket_client);
}

3、UDP服务器

/* UDP协议中服务器的程序 */
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <netinet/in.h>
#include <stdlib.h>

#define portnum 3333 //定义端口号

void main()
{
    int socket_server;//服务器套接字标识符
    struct sockaddr_in server_addr;//服务器地址,使用的是IPV4地址结构
    struct sockaddr_in client_addr;//客户机地址,使用的是IPV4地址结构
    int size_addr;//记录地址的长度
    char receive_buffer[128];//接收到的数据存放的位置
    int receive_nbytes;//接收到的字节数目

    //创建socket  套接字
    socket_server = socket(AF_INET, SOCK_DGRAM, 0);
    if (socket_server == -1)//失败就退出
    {
        printf("creat socket of server fail.\n");
        exit(1);
    }

    //设置要绑定的服务器地址
    bzero(&server_addr, sizeof(struct sockaddr_in));//清零
    server_addr.sin_family = AF_INET;//协议族
    server_addr.sin_port = htons(portnum);//端口号,且 转换为网络字节序
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    //绑定所有的IP地址,转换为网络字节序

    //绑定地址  
    bind(socket_server, (struct sockaddr *) (&server_addr),
     sizeof(struct sockaddr));

    size_addr = sizeof(struct sockaddr *);//地址长度
    while(1)
    {
        //接收客户机数据
        bzero(receive_buffer, sizeof(receive_buffer));
        receive_nbytes = recvfrom(socket_server, receive_buffer, 128, 0,
         (struct sockaddr *)(&client_addr), (socklen_t *)(&size_addr));
        receive_buffer[receive_nbytes] = '\0';//添加结束符
        printf("server received %s\n", receive_buffer);
    }

    //结束连接
    close(socket_server);
}

4、UDP客户端

/* UDP协议中客户机的程序 */
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <netinet/in.h>
#include <stdlib.h>

#define portnum 3333  //定义端口号

void main(int argc, char **argv)
{
    int socket_client;//服务器套接字标识符
    struct sockaddr_in server_addr;//服务器地址,使用的是IPV4地址结构
    struct sockaddr_in client_addr;//客户机地址,使用的是IPV4地址结构
    char buffer[128];//发送的数据存放的位置
    int nbytes;//发送的字节数目

    //创建socket  套接字
    socket_client = socket(AF_INET, SOCK_DGRAM, 0);
    if (socket_client == -1)//失败就退出
    {
        printf("creat socket of client fail.\n");
        exit(1);
    }

    //设置要发送数据的的目的地址
    bzero(&server_addr, sizeof(struct sockaddr_in));//清零
    server_addr.sin_family = AF_INET;//协议族
    server_addr.sin_port = htons(portnum);//端口号,且 转换为网络字节序
    server_addr.sin_addr.s_addr = inet_addr(argv[1]);
    //输入IP地址
    //指定IP地址,转换为整数类型的地址,已经是网络字节序

    while(1)
    {
        bzero(buffer, 128);
        //发送数据
        printf("Please input char.\n");
        fgets(buffer, 128, stdin);
        sendto(socket_client, buffer, strlen(buffer), 0,
         (struct sockaddr *)(&server_addr), sizeof(server_addr));
    }

    //结束连接
    close(socket_client);
}
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值