LINUX网络编程

服务器端:
创建socket:int socket(int domain, int type, int protocal);

参数1:域 AF_INET(ipv4) AF_INET6 (ipv6)

参数2:类型 SOCK_DGRAM(udp协议) SOCK_STREAM (tcp协议)

参数3:默认0即可

绑定地址:int bind(int sockfd, const struct sockaddr* addr, socklen_t len);

参数1:socket描述符

参数2:地址结构体

​ //通用的地址【此处所用的结构体】
struct sockaddr{
sa_family_t sa_family; //协议族
char sa_data[14]; //地址
}
//ipv4地址【ipv4专用,我们平常所用的最多】
struct sockaddr_in{
short int sin_family; //协议族
unsigned short int sin_port; //端口号
struct in_addr sin_addr; // IP地址【结构体原型在下面】
unsigned char sin_zero[8]; //填充
}
struct in_addr{
unsigned long s_addr; // IP地址 4字节整数
}

补充1:字符串形式的IP地址与整数形式的IP地址转化

从上面可以看到,我们用的地址是整数型的;而我们平常在现实生活中所看到的地址:例如:192.168.1.1是字符串型的;

地址转化函数:

in_addr_t inet_addr(const char* cp); //将192.168.1.1转化为整数型的IP地址(网络字节序)

举例:in_addr.saddr = inet_addr(“192.168.1.1” );

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

补充2:网络字节序

补充2.1:大端和小端模式

要想知道网络字节序是什么?首先需要知道大端和小端模式;简而言之:大端模式,是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中 ;小端模式,是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中 ;

具体知识请参考https://blog.csdn.net/litter_driver777/article/details/51636311。

我们自己电脑可能是大端,也可能是小端的;同样,别人的电脑也有可能是大端或者小端的,所以在网络上传输数据时,我们就需要统一他们的大小端模式。

规定网络中传输的是大端模式,所以网络字节序是大端模式的;

主机字节序和网络字节序转化函数:

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

​ //举例: in_addr.saddr = htonl(INADDR_ANY)

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

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

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

监听:int listen(int sockfd, int backlog);

参数1:socket描述符

参数2:backlog 允许连接的客户机的数目

等待连接:int accept(int sockfd, struct sockaddr* reStrict addr, socklen_t* restrict len);

参数1:socket描述符

参数2:客户机的地址(接收到的)

参数3:地址长度的指针(注意:是指针哦,不是整形)

返回值:新的套接字的fd(记住了:以后收发用这个新的sockfd哦!)

发送:ssize_t send(int sockfd, const void* buf, size_t nbytes, int flags);

参数1:新的套接字的fd(accept的返回值)

参数2:要发送的数据

参数3:数据的长度

参数4:默认为0即可

接收:ssize_t recv(int sockfd, void* buf, size_t nbytes, int flags);

关闭连接close():

客户机端:
连接服务器:connect(int sockfd, const struct sockaddr* addr, socklen_t len);

参数1:socket描述符

参数2:要连接的服务器的地址

参数3:地址长度—整形

其余函数参考服务器端的讲解。

代码:
服务器code:

#include <stdio.h>
#include <sys/socket.h>
#include <string.h>
#include <netinet/in.h>

#define portnum 3333

int main()
{
    int sockfd;
    int new_fd;
    struct sockaddr_in server_addr;
    struct sockaddr_in client_addr;
    char buffer[128];
    int nByte;
    int sin_size;
    
    //1.创建套接字
    if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    {
        printf("create socket error!\n");
        exit(1);
    }
    
    //2.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);
        
    //2.绑定地址
    bind(sockfd,(struct sockaddr*)(&server_addr),sizeof(struct sockaddr));
    
    //3.监听端口
    listen(sockfd,5);
        
    while(1)
    {
        //4.等待连接
        sin_size = sizeof(struct sockaddr);
        new_fd = accept(sockfd,(struct sockaddr*)(&client_addr),&sin_size);//注意:第3个参数为socklen_t*(整形的指针)
        printf("server get connection from %s\n",inet_ntoa(client_addr.sin_addr)); //将整数型的IP地址转化为字符型(192.168.1.1)
        
        //5.接收数据
        nByte = recv(new_fd, buffer, 128, 0);
        buffer[nByte] = '\0';
        printf("server reciivd : %s\n", buffer);
        
        //6.结束连接
        close(new_fd);
    }    
    
    close(sockfd);
    
    return 0;
    
}    
客户端code:

#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>

#define portnum 3333

int main()
{
    struct sockaddr_in server_addr;
    char buffer[128];
    
    //1.创建套接字
    int sockfd;
    if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    {
        printf("create socket error!\n");
        exit(1);
    }
    
    //2.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.103.100");
    
    //2.连接服务器
    if(connect(sockfd,(struct sockaddr*)(&server_addr),sizeof(struct sockaddr)) == -1)
    {
        printf("connect error\n");
        exit(1);
    }
    
    //3.发送数据到服务器
    printf("please input char:\n");
    fgets(buffer,128,stdin);
    send(sockfd, buffer, strlen(buffer), 0);
    
    //4.关闭连接
    close(sockfd);
    
    return 0;
    
}

下面是别人的网络编程文章,觉得不错,附上链接

一、基础理论篇

01、网络协议入门

02、LAN、WAN、WLAN、VLAN 和 VPN 的区别

03、IP 地址介绍

04、广播地址介绍

05、无连接和面向连接协议的区别

06、因特网的IP协议是不可靠无连接的,那为何当初不直接把它设计为可靠?

07、C/S和B/S架构的区别

 

二、初级实践篇

08、编程准备:字节序、地址转换

09、套接字的介绍

10、UDP编程

11、绑定( bind )端口需要注意的问题

12、UDP广播

13、UDP多播

14、TCP编程

15、TCP中connect()、listen()和accept()三者的关系

16、浅谈 TCP 三次握手和四次挥手

17、并发服务器的三种实现模型

 

三、进阶高级篇

18、原始套接字能干什么?

19、原始套接字编程

20、原始套接字实例:MAC 头部报文分析

21、原始套接字实例:MAC 地址扫描器

22、IP 数据报格式详解

23、TCP 和 UDP 数据报格式详解

24、原始套接字实例:发送 UDP 数据包

25、libpcap详解

26、libnet使用指南

 

 

四、拓展知识篇

27、杀毒软件和防火墙的区别

28、iptables使用说明

29、内网和外网之间的通信

30、抓包工具 Wireshark 使用介绍

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小薛1988

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值