linux系统编程(网络编程)

参考:(1条消息) 【Linux系统编程】网络编程_大头1213的博客-CSDN博客

    • 概述

1、tcp与udp的区别

1.TCP面向连接(如打电话要先拨号建立连接);UDP是无连接的,即发送数据之前不需要建立连接;
2.TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付;
3. TCP面向字节流,实际上是TCP把数据看成一连串无结构的字节流;UDP是面向报文的UDP没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低(对实时应用很有用,如IP电话,实时视频会议等);
4. 每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信;
5. TCP首部开销20字节;UDP的首部开销小,只有8个字节;
6. TCP的逻辑通信信道是全双工的可靠信道,UDP则是不可靠信道。

2、端口号

端口号的主要作用是表示一台计算机中的特定进程所提供的服务。网络中的计算机是通过IP地址来代表其身份的,它只能表示某台特定的计算机,但是一台计算机上可以同时提供很多个服务,如数据库服务、FTP服务、Web服务等,我们就通过端口号来区别相同计算机所提供的这些不同的服务,如常见的端口号21表示的是FTP服务,端口号23表示的是Telnet服务,端口号25指的是SMTP服务等。端口号一般习惯为4位整数,在同一台计算机上端口号不能重复,否则,就会产生端口号冲突。

3.IP地址

IP地址是指互联网协议地址,是我们进行TCP/IP通讯(因特网互联协议)的基础,每个连接到网络上的计算机都必须有一个IP地址,类似于打电话的”电话号码“。

二.字节序

1、字节序概念:

字节序是计算机存储多字节数据的方式,目前主流的方式有:大端字节序和小端字节序,字节序主要是针对多字节的数据类型,比如 short、int 等类型,在跨平台和网络编程中,时常要考虑的问题。

1. Big-Endian(大端字节序):高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。
2.Little-Endian(小端字节序):低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。
3.网络字节序 = 大端字节序

2、字节序的深入

例如:

对于数据 0x12345678,假设从地址0x4000开始存放,在大端和小端模式下,存放的位置分别为:

内存地址

小端模式

大端模式

0x4003

0x12

0x78

0x4002

0x34

0x56

0x4001

0x56

0x34

0x4000

0x78

0x12

采用Little-endian模式的CPU对操作数的存放方式是从低字节到高字节,而Big-endian模式对操作数的存放方式是从高字节到低字节。

小端存储后:0x78563412 大端存储后:0x12345678

3、字节序转换的相关API

#include <netinet/in.h>

uint16_t htons(uint16_t host16bitvalue); //返回网络字节序的值
uint32_t htonl(uint32_t host32bitvalue); //返回网络字节序的值
uint16_t ntohs(uint16_t net16bitvalue); //返回主机字节序的值
uint32_t ntohl(uint32_t net32bitvalue); //返回主机字节序的值

h代表host,n代表net,s代表short(两个字节),l代表long(4个字节),通过上面的4个函数可以实现主机字节序和网络字节序之间的转换。有时可以用INADDR_ANY,INADDR_ANY指定地址让操作系统自己获取

三、socket(套接字)

socket是对TCP/IP协议的封装,它的出现只是使得程序员更方便地使用TCP/IP协议栈而已。socket本身并不是协议,它是应用层与TCP/IP协议族通信的中间软件抽象层,是一组调用接口(TCP/IP网络的API函数)

总流程:

服务端流程:

客户端流程:

1、使用socket()函数创建套接字
2、调用connect()函数建立一个与TCP服务器的连接
3、发送数据请求,接收服务器的数据应答
4、终止连接
四、相关函数

1.socket函数

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
 
int socket(int domain, int type, int protocol);

2.bind() 函数

用于绑定IP地址和端口号到socket fd

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

//sockfd:是一个socket描述符
//addr:是一个指向包含有本机IP地址及端口号等信息的sockaddr类型的指针,指向要绑定给sockfd的协议地址结构这个地址结构根据地址创建socket 时的地址协议族的不同而不同

3.listen()函数

listen函数使用主动连接 套接字 变为被连接 套接口 ,使得一个进程可以接受其它进程的请求,从而成为一个服务器进程。 在 TCP 服务器编程中listen函数把进程变为一个服务器,并指定相应的套接字变为被动连接。 listen函数一般在调用bind之后-调用accept之前调用。

int listen(int sockfd, int backlog);
//参数:
//sockfd:sockfd是socket系统调用返回的服务器端socket描述符
//backlog:backlog指定在请求队列中允许的最大请求数

4.accept()函数

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

5.connect()函数

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
地址转换API

int inet_aton(const char* straddr,struct in_addr *addrp);
//把字符串形式的“192.168.1.123”转为网络能识别的格式

char* inet_ntoa(struct in_addr inaddr);
//把网络格式的ip地址转为字符串形式

6.数据收发

五、编程实现

实现双方聊天

server.c

#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
//#include <linux/in.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <stdlib.h>

int main(int argc,char **argv)
{

        int s_fd;
        int c_fd;
        int n_read;
        char readBuf[128];
        char *msg="i get your connect";//定义一个指针字符串
        struct sockaddr_in s_addr;//定义服务端 sockaddr_in类型的结构体s_addr
        struct sockaddr_in c_addr;//定义客户端 sockaddr_in类型的结构体c_addr

        memset(&s_addr,0,sizeof(struct sockaddr_in));//为s_addr开辟内存空间
        memset(&c_addr,0,sizeof(struct sockaddr_in));//为c_addr开辟内存空间

        //1.socket
        s_fd=socket(AF_INET,SOCK_STREAM,0);//创建套接字,返回一个描述符s_fd
        if(s_fd == -1){
                perror("socket");
                exit(-1);
        }


        s_addr.sin_family=AF_INET;//设置协议族为tcp协议
        s_addr.sin_port=htons(atoi(argv[2]));//设置端口号
        inet_aton(argv[1],&s_addr.sin_addr);//把字符串形式的“192.168.1.123”转为网络能识别的格式
        //2.bind
        bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));//绑定套接字添加信息
        //3.listen
        listen(s_fd,10);//设置套接字为监听模式
        //4.accept  
        int clen=sizeof(struct sockaddr_in);
        while(1){

                c_fd =accept(s_fd,(struct sockaddr *)&c_addr,&clen);//接收客户端的连接请求,返回描述符c_fd
                if(c_fd == -1){

                        perror("accept");
                }

                printf("get connect:%s\n",inet_ntoa(c_addr.sin_addr));//获取客户端地址,把网络格式的ip地址转为字符串形式
                if(fork() == 0){
        //5.read
                        n_read=read(c_fd,readBuf,128);//创建子进程去读取数据
                        if(n_read ==-1){
                                perror("read");
                        }else{
                                printf("get message:%d,%s\n",n_read,readBuf);
                        }

                        write(c_fd,msg,strlen(msg));//子进程发送数据
                        break;
                }

                }
        return 0;
}

client.c

#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
//#include <linux/in.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <stdlib.h>


int main(int argc,char **argv)
{

        int c_fd;
        int n_read;
        char readBuf[128];
        char *msg="msg from client";

        struct sockaddr_in c_addr;

        memset(&c_addr,0,sizeof(struct sockaddr_in));

        //1.socket
        c_fd=socket(AF_INET,SOCK_STREAM,0);
        if(c_fd == -1){
                perror("socket");
                exit(-1);
        }


        c_addr.sin_family=AF_INET;
        c_addr.sin_port=htons(atoi(argv[2]));
        inet_aton(argv[1],&c_addr.sin_addr);

        //2.connect
        if(connect(c_fd,(struct sockaddr *)&c_addr,sizeof(struct sockaddr_in)) == -1){

                perror("connect");
                exit(-1);
        }


        //6.send
        write(c_fd,msg,strlen(msg));

        //5.read
        n_read=read(c_fd,readBuf,128);
        if(n_read ==-1){
                perror("read");
        }else{
                printf("get message from message:%d,%s\n",n_read,readBuf);
        }
        return 0;
}

server1.c(相对于上面server.c加上主函数调参)

#include <stdio.h>

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
//#include <linux/in.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <stdlib.h>
int main(int argc,char **argv)//main调参
{

        int s_fd;
        int c_fd;
        int n_read;
        int mark=0;//添加标志位
        char readBuf[128];
//      char *msg="i get your connect";
        char msg[128]={0};
        struct sockaddr_in s_addr;
        struct sockaddr_in c_addr;

        if(argc !=3){

                printf("param is not good\n");
                exit(-1);
        }
        memset(&s_addr,0,sizeof(struct sockaddr_in));
        memset(&c_addr,0,sizeof(struct sockaddr_in));

        //1.socket
        s_fd=socket(AF_INET,SOCK_STREAM,0);
        if(s_fd == -1){
                perror("socket");
                exit(-1);
        }


        s_addr.sin_family=AF_INET;
        s_addr.sin_port=htons(atoi(argv[2]));
        inet_aton(argv[1],&s_addr.sin_addr);
        //2.bind
        bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));
        //3.listen
        listen(s_fd,10);
        //4.accept
        int clen=sizeof(struct sockaddr_in);
        while(1){

                c_fd =accept(s_fd,(struct sockaddr *)&c_addr,&clen);
                if(c_fd == -1){

                        perror("accept");
                }

                mark++;//当有客户端加入记录
                printf("get connect:%s\n",inet_ntoa(c_addr.sin_addr));

                if(fork() == 0){
           //5.read
                        if(fork() ==0){
                                while(1){

                                sprintf(msg,"welcome NO.%d client",mark);
                                write(c_fd,msg,strlen(msg));
                                sleep(3);
                                }
                        }

                        while(1){
                        memset(readBuf,0,sizeof(readBuf));
                        n_read=read(c_fd,readBuf,128);
                        if(n_read ==-1){
                                perror("read");
                        }else{
                                printf("get message:%d,%s\n",n_read,readBuf);
                        }
                        }
                        break;
                }

                }
        return 0;
}

client1.c

#include <stdio.h>

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
//#include <linux/in.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <stdlib.h>
int main(int argc,char **argv)
{

        int c_fd;
        int n_read;
        char readBuf[128];
//      char *msg="msg from client";
        char msg[128]={0};
        struct sockaddr_in c_addr;

        memset(&c_addr,0,sizeof(struct sockaddr_in));

        if(argc !=3){

                printf("param is not good\n");
                exit(-1);
        }

        //1.socket
        c_fd=socket(AF_INET,SOCK_STREAM,0);
        if(c_fd == -1){
                perror("socket");
                exit(-1);
        }


        c_addr.sin_family=AF_INET;
        c_addr.sin_port=htons(atoi(argv[2]));
        inet_aton(argv[1],&c_addr.sin_addr);
        //2.connect
        if(connect(c_fd,(struct sockaddr *)&c_addr,sizeof(struct sockaddr_in)) == -1){

                perror("connect");
                exit(-1);
        }

        while(1){

                if(fork() == 0){
                        while(1){
                        memset(msg,0,sizeof(msg));
                        printf("input: ");
                        gets(msg);
                        write(c_fd,msg,strlen(msg));
                        }
                }
                while(1){
                memset(readBuf,0,sizeof(readBuf));
                n_read=read(c_fd,readBuf,128);
                if(n_read ==-1){
                        perror("read");
                }else{
                        printf("get message from message:%d,%s\n",n_read,readBuf);
                }
                }
        }
        //6.send

        //5.read

        return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Linux系统编程中,网络编程是指使用套接字(socket)接口进行进程间通信的编程技术。网络编程允许在同一台计算机上运行的进程以及不同计算机上的进程相互通信。通过网络编程,可以使用TCP/IP协议栈(一般需要用到TCP协议和UDP协议)进行通信。 网络编程主要涉及以下内容: 1. 引言:介绍网络编程的基本概念和背景。 2. TCP/UDP对比:比较TCP和UDP两种传输协议的特点和适用场景。 3. 端口号作用:解释端口号在网络编程中的作用。 4. 字节序:讲解网络字节序和主机字节序的转换。 5. socket函数:介绍socket函数用于创建套接字。 6. bind函数:说明bind函数用于将套接字与指定的IP地址和端口号绑定。 7. listen函数:介绍listen函数用于设置套接字的监听队列。 8. accept函数:解释accept函数用于接受客户端的连接请求。 9. write和read函数:说明write和read函数用于在套接字上发送和接收数据。 10. send和recv函数:介绍send和recv函数用于在套接字上发送和接收数据。 11. connect函数:讲解connect函数用于建立与服务器的连接。 网络编程的具体实现可以参考示例代码中的客户端代码,该代码使用了socket函数创建套接字,connect函数建立与服务器的连接,并使用write和read函数进行数据的发送和接收。 总之,Linux系统编程中的网络编程是一种使用套接字接口进行进程间通信的技术,通过TCP/IP协议栈实现数据的传输。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [linux系统编程网络编程](https://blog.csdn.net/qq_52551323/article/details/119804340)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值