Linux-系统编程-网络编程

  1. 先前讲的进程间通信:管道、消息队列、共享内存、信号、信号量都是依赖Linux内核调度。(原理是用户层调用C库接口产生软中断使得程序切入内核态运行,由内核对应C库接口的系统调用system函数来操作底层硬件如:驱动、磁盘IO)依赖内核的通信导致只能在本机的不同进程间通信,没办法实现异机通信。所以得引入网络编程才可以实现不同计算机上的进程间通信。
  2. 网络编程两大核心要素:

2.1地址(在网络中找到对应的计算机)

地址又包含了:IP地址和端口号

      1. IP地址:标识哪一台设备(设备在网络中的楼号)
      2. 端口号:一台设备上会跑ftp/http/socket1/socket2/pubg吃鸡等多个服务程序。 端口号是帮助确定与ftp/http/socket1/socket2/pubg吃鸡中的哪一个服务程序通信。

pubg吃鸡的端口号是8880,就可以通过调用接口传参8880来与pubg吃鸡程序通 信。

2.2数据交流(找到对应的计算机后传输数据:聊天)

2.2.1要聊天就得讲一样的语言,双方要有一样通信协议(http/tcp/mpp)协议就是 数据格式。

  1. 入门级的网络编程:socket套接字网络编程(用tcp/mpp协议)
  2. socket套接字网络编程的两种数据协议

4.1 tcp协议:侧重点对点(面向连接),看重数据的准确性,精准拨号交流。比较可靠。

4.2 udp协议:侧重数据量。不看重数据的准确性。应用在数据量大且数据流快的场景。

4.3端口号选择5000-10000以上。

  1. 字节序有两种

5.1大端字节序==网络字节序(起始放低位)

5.2小端字节序==X86数据存储方式(起始放高位)

5.3字节序是指多字节数据在计算机内存中存储或网络传输时各字节的存储顺序。

5.4一个字节==8bit(位);一个字==两个字节==16bit(位);双字==四个字节==32bit(位);

5.5双字0x01 02 03 04;LE(小端存储):04 03 02 01;BE(大端存储):01 02 03 04

  1. socket服务器开发流程
  1. 创建套接字

//int socket(int domain, int type, int protocol);

其中int domain配为AF_INET表示互联网协议(TCP/IP族)

其中int type配为SOCK_STREAM表示TCP协议(配为SOCK_DGRAM表示UDP协议)

其中int protocol配为0表示内核默认以TCP协议来操作系统调用函数

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

  1. 为创建好的套接字添加信息(IP地址和端口号)

//int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);

其中int sockfd是socket返回的句柄标识符

其中 const struct sockaddr *addr是一个结构体指针,同等替换为struct sockaddr_in结构体,

配置结构体中.sin_family=AF_INET(表示互联网协议TCP/IP族);

配置结构体中.sin_port=htons(atoi(argv[2]))配置端口号

atoi(argv[2])函数表示把C语言文件的第三个参数字符转化成int型。

htons是一个把X86字节序转换成网络字节序的API。保证字节序格式的正确 性。否则传输的数据会乱码。

配置结构体中.sin_addrinet_aton(argv[1],&saddr.sin_addr);配置IP地址

inet_aton函数把C语言文件的第二个参数转化成网络可以识别的形式放 入.sin_addr

结构体中第四个成员可以不配置。

bind(s_fd,(struct sockaddr *)&saddr,sizeof(struct sockaddr));

  1. 监听网络连接

//int listen(int sockfd, int backlog);

其中int sockfd是socket返回的句柄标识符

其中int backlog是监听的设备个数可以是20

listen(s_fd,20);

  1. 监听到有客户端接入,接收一个连接

//int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

其中int sockfd是socket返回的句柄标识符

创建一个结构体struct sockaddr_in caddr;这个结构体是客户端与服务器数据交流的 数据容器

其中socklen_t *addrlen是结构体struct sockaddr_in的大小

c_fd=accept(s_fd,(struct sockaddr *)&caddr,&len);

  1. read/write读写操作

write(c_fd,msg,strlen(msg));

read(c_fd,Rbuf,1024);

其中c_fd是accept返回的句柄标识符

  1. 关闭套接字,断开连接

close(c_fd);

7.结构体struct sockaddr_in {

  __kernel_sa_family_t  sin_family;  /* Address family协议族*/

  __be16                sin_port; /* Port number端口号*/

  struct in_addr        sin_addr;   /* Internet address地址IP*/

  /* Pad to size of `struct sockaddr'. 没有实际意义,只是为了与sockaddr格式对齐,不用配置*/

  unsigned char         __pad[__SOCK_SIZE__ - sizeof(short int) -

                        sizeof(unsigned short int) - sizeof(struct in_addr)];

};

  1. 网络IP地址与字符串相转换函数

7.1 int inet_aton(const char *cp, struct in_addr *inp);//把字符串“192.168.0.1”转换为网 络可以识别的格式

7.2 char *inet_ntoa(struct in_addr in);//把网络IP地址转换为字符串“192.168.0.1”格式

8.端口号用的字节序转换函数(网络字节序与X86字节序相互转换)

8.1主机字节序转换->网络字节序(s表示短字节;常用/l表示长字节)

uint32_t htonl(uint32_t hostlong);

uint16_t htons(uint16_t hostshort);

8.2网络字节序转换->主机字节序(s表示短字节;常用/l表示长字节)

uint32_t ntohl(uint32_t netlong);

uint16_t ntohs(uint16_t netshort);

9.服务器示例代码:

#include <stdio.h>

#include <sys/types.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <arpa/inet.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>

//int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

//int socket(int domain, int type, int protocol);

//int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);

//int inet_aton(const char *cp, struct in_addr *inp);

//char *inet_ntoa(struct in_addr in);

//int listen(int sockfd, int backlog);

int main(int argc,char **argv)

{

int c_fd;

char Rbuf[1024]={0};

char msg[1024]={0};

int nr;

//1.socket

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

if(s_fd==-1)

{

perror("socket");

}

//2.bind

struct sockaddr_in saddr=

{

.sin_family=AF_INET,

.sin_port=htons(atoi(argv[2]))

};

inet_aton(argv[1],&saddr.sin_addr);

bind(s_fd,(struct sockaddr *)&saddr,sizeof(struct sockaddr));

//3.listen

listen(s_fd,20);

//4.accept

struct sockaddr_in caddr;

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

int len=sizeof(struct sockaddr);

while(1)

{

c_fd=accept(s_fd,(struct sockaddr *)&caddr,&len);

if(c_fd==-1)

{

perror("accept");

}else

{

puts("connect!");

}

printf("from %s\n",inet_ntoa(caddr.sin_addr));

if(fork()==0)

{

nr=read(c_fd,Rbuf,1024);

if(nr==-1)

{

perror("read");

}else

{

printf("read %d byte:%s\n",nr,Rbuf);

}

//5.read/write

if(fork()==0)

{

puts("please input!");

                                memset(msg,0,strlen(msg));

                                gets(msg);

                                write(c_fd,msg,strlen(msg));

}

}

}

//6.close

close(c_fd);

return 0;

}

  1. 客户端代码实现流程

A.创建套接字

//int socket(int domain, int type, int protocol);

其中int domain配为AF_INET表示互联网协议(TCP/IP族)

其中int type配为SOCK_STREAM表示TCP协议(配为SOCK_DGRAM表示UDP协议)

其中int protocol配为0表示内核默认以TCP协议来操作系统调用函数

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

B.连接服务器

//int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);

其中int sockfd是socket返回的句柄标识符

其中 const struct sockaddr *addr是一个结构体指针,同等替换为struct sockaddr_in结构 体,配置结构体中.sin_family=AF_INET(表示互联网协议TCP/IP族);

配置结构体中.sin_port=htons(atoi(argv[2]))配置端口号

atoi(argv[2])函数表示把C语言文件的第三个参数字符转化成int型。

htons是一个把X86字节序转换成网络字节序的API。保证字节序格式的正确 性。 否则传输的数据会乱码。

配置结构体中.sin_addrinet_aton(argv[1],&saddr.sin_addr);配置IP地址

inet_aton函数把C语言文件的第二个参数转化成网络可以识别的形式放 入.sin_addr

结构体中第四个成员可以不配置。

connect(c_fd,(struct sockaddr *)&caddr,sizeof(struct sockaddr));

  1. read/write读写操作

write(c_fd,msg,strlen(msg));

read(c_fd,Rbuf,1024);

其中c_fd是accept返回的句柄标识符

D.关闭套接字,断开连接

close(c_fd);

11.客户端示例代码:

#include <stdio.h>

#include <sys/types.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <arpa/inet.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>

//int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

//int socket(int domain, int type, int protocol);

//int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);

//int inet_aton(const char *cp, struct in_addr *inp);

//char *inet_ntoa(struct in_addr in);

//int listen(int sockfd, int backlog);

//int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);

int main(int argc,char **argv)

{

char Rbuf[1024]={0};

int nr;

char msg[1024]={0};

//1.socket

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

if(c_fd==-1)

{

perror("socket");

}

//2.connect

struct sockaddr_in caddr=

        {

                .sin_family=AF_INET,

                .sin_port=htons(atoi(argv[2]))

        };

        inet_aton(argv[1],&caddr.sin_addr);

connect(c_fd,(struct sockaddr *)&caddr,sizeof(struct sockaddr));

puts("connect!");

while(1)

{

if(fork()==0)

{

puts("please input!");

                memset(msg,0,strlen(msg));

                gets(msg);

                write(c_fd,msg,strlen(msg));

}

//3.read/write

nr=read(c_fd,Rbuf,1024);

if(nr==-1)

{

perror("read");

}else

{

printf("read %d byte:%s\n",nr,Rbuf);

}

}

//6.close

close(c_fd);

return 0;

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值