Linux网络编程相关操作

一、Linux网络编程基础知识
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则是不可靠通信

端口号的作用
一台拥有IP地址的主机可以提供许多服务,比如Web服务、FTP服务、SMTP服务等,这些服务完全可以通过一个IP地址来实现。那么主机是怎么样区分不同的网络服务呢?显然不能只靠IP地址,因为IP地址与网络服务的关系是一对多的关系。实际上是通过 “IP地址+端口号” 来区分不同的服务的。端口提供了一种访问通道,服务器一般都是通过知名端口号来识别的。例如,对于每个TCP/IP实现来说,FTP服务器的TCP端口号都是21,每个Telnet服务器的TCP端口号都是23,每个TFTP(简单文件传输协议)服务器的UDP端口号都是69。

socket概念
Linux中的网络编程是通过socket接口来进行的。socket是一种特殊的I/O接口,它也是一种文件描述符。它是一种常用的进程之间通信机制,通过它不仅能实现本地机器上的进程之间的通信,而且通过网络能够在不同机器上的进程之间进行通信。
每一个socket都用一个半相关描述{协议、本地地址、本地端口}来表示;一个完整的套接字则用一个相关描述{协议、本地地址、本地端口、远程地址、远程端口}来表示。socket也有一个类似于打开文件的函数调用,该函数返回一个整型的socket描述符,随后的连接建立、数据传输等操作都是通过socket来实现的。
socket信息数据结构
(现如今使用较少了)
struct sockaddr

{
unsigned short sa_family; /地址族/

 char sa_data[14]; /*14字节的协议地址,包含该socket的IP地址和端口号。*/

};

(使用优化版居多)
struct sockaddr_in

{
short int sa_family; /地址族/

 unsigned short int sin_port; /*端口号*/

 struct in_addr sin_addr; /*IP地址*/

 unsigned char sin_zero[8]; /*填充0 以保持与struct sockaddr同样大小*/

};

struct in_addr

{
unsigned long int s_addr; /* 32位IPv4地址,网络字节序 */

};

字节序
字节序是指多字节数据在计算机内存中存储或者网络传输时各字节的存储顺序。
1. Little endian:将低序字节存储在起始地址(小端字节序)
2. Big endian:将高序字节存储在起始地址(大端字节序)
网络字节序=大端字节序
在这里插入图片描述
字节序的转换
在这里插入图片描述

地址转换API
在这里插入图片描述
socket服务和客户端开发步骤
在这里插入图片描述
socket()参数描述
在这里插入图片描述
bind()的参数描述
在这里插入图片描述
listen()参数描述
在这里插入图片描述
accept()参数描述
在这里插入图片描述
connect()参数描述
在这里插入图片描述
二、实现双方聊天
服务端

#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<stdlib.h>
#include<string.h>
//#include <unistd.h>

int main(int argc,char **argv)
{
    
    
        int s_fd;
        int c_fd;
        int n_read;
        char readBuf[128];
        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]));//,转换为网络字节序;注意转换成整型数,将字符串转换成整型数
//      s_addr.sin_addr.s_addr=inet_aton("127.0.0.1");//yong fa chuowu

//       int inet_aton(const char *cp, struct in_addr *inp);
        inet_aton(argv[1],&s_addr.sin_addr);//将字符串形式的地址转为网络能识别的形序,赋给&s_addr.sin_addr
        
        //2.bind
//       int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
        bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));

        //3.listen
        listen(s_fd,10);

        //4.accept
//int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
        int clen=sizeof(struct sockaddr);
        while(1){
    
    

                c_fd=accept(s_fd,(struct sockaddr *)&c_addr,&clen);//注意第三给参数是个子针,没有客户端连接的时候会阻塞
                if(c_fd==-1){
    
    
                        perror("accept");
                }
                printf("get connect: %s\n",inet_ntoa(c_addr.sin_addr));//把网络格式的地址转为字符串形式,在服务端显示客户端的地址

                if(fork()==0){
    
       //新客户端接入的时候调用子进程
                        if(fork()==0){
    
    
                                while(1){
    
    
                                        memset(msg,0,sizeof(msg));
                                        printf("input: ");
                                        gets(msg);
                                        //6.write
                                        write(c_fd,msg,strlen(msg));
                                        }
                                }
//先获取客户端的输入,若无数据的输入则阻塞                               
                        while(1){
    
    
                                memset(readBuf,0,sizeof(readBuf));
                                //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);
                                }
                        }
                        break;
                }

        }

        return 0;
}

客户端

#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<stdlib.h>
#include<string.h>
//#include <unistd.h>

int main(int argc,char **argv)
{
    
    
        int c_fd;
        int n_read;
        char readBuf[128]; 
        char msg[128]={
    
    0};

        struct sockaddr_in c_addr;

        if(argc !=3){
    
    
                printf("param is not good\n");
                exit(-1);
        }

        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]));
//      s_addr.sin_addr.s_addr=inet_aton("127.0.0.1");  //inet_aton()用法错误

//       int inet_aton(const char *cp, struct in_addr *inp);
        inet_aton(argv[1],&c_addr.sin_addr);


        //2.connect
// int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
        if(connect(c_fd,(struct sockaddr *)&c_addr,sizeof(struct sockaddr)) == -1){
    
    
                perror("connect");
                exit(-1);
        }
        
        while(1){
    
    
                if(fork()==0){
    
          // 子进程不断的写
                        while(1){
    
    
                        memset(msg,0,sizeof(msg));
                        printf("input: ");
                        gets(msg);
                         //3.wr1ite
                        write(c_fd,msg,strlen(msg));
                        }
                }
									
 //先执行父进程,即一下语句  		 
                        while(1){
    
    	//父进程不断的读取
                        memset(readBuf,0,sizeof(readBuf));
                        //4.read
                        n_read=read(c_fd,readBuf,128);  //在没有读取到信息的时候会阻塞
                        if(n_read==-1){
    
    
                                perror("read");
                        }else{
    
    
                                printf("get message from server:%d,%s\n",n_read,readBuf);
                        }
                }
        }
        return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_46777053/article/details/109001938