linux系统编程之网络编程

23 篇文章 0 订阅
1.网络编程的概念

在学习了进程之间的通信(管道,消息队列,信号,共享内存,信号量)之后,发现他们都有一个特点,那就是依赖于内核,只能做到在同一台设备中的两个进程进行相互沟通。而网络编程通过某种协议,将想要发送或着接收的数据打包/解析,可以实现通过网络,处于不同终端的进程进行通信。网络编程必须的有两点,数据和地址,地址包括IP地址和端口号。
端口号的作用是用来区分不同服务的。

2. 字节序

字节序是指多字节数据在计算机内存中存储或者网络传输时个字节的存储顺序。
常见序:

  • 小端字节序——将低序字节存储在起始地址
  • 大端字节序——将高序字节存储在起始地址

网络字节序是大端字节序。
x86系列CPU都是小端字节序。

3. Socket套接字

3.1 TCP/UDP协议

TCP : 该协议面向连接,连接可靠,传输的数据相对比较小。
UDP : 该协议面向报文,连接不可靠,传输的数据量大。

两者对比:
在这里插入图片描述

3.2 相关API
开发步骤:
在这里插入图片描述

服务器socket开发步骤:

  1. 创建套接字socket()。
  2. 为套接字添加信息(IP地址和端口号)bind()。
  3. 监听网络变化listen()。
  4. 监听到网络变化,说明有客户端接入,就接受一个连接accept()。
  5. 数据交互read,write
  6. 关闭套接字 close()

客户端套接字开发步骤:

  1. 创建套接字
  2. 连接服务器connect()
  3. 读写数据
  4. 关闭套接字

原型:

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
// 参数说明见下图
int socket(int domain, int type, int protocol);
// 参数说明见下图,一般使用下面的结构体
int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
//参数见下图
int listen(int sockfd, int backlog);
// 若不关系客户端地址和长度,后两个传NULL
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
  
 // IP地址转换API    
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
// 将点分十进制转换为网络能识别的格式
int inet_aton(const char *cp, struct in_addr *inp);
// 将网络格式的IP地址转为字符串形式
char *inet_ntoa(struct in_addr in);

// 字节序转换API
#include <arpa/inet.h>
//  h代表host本地主机,n表示网络,s表示short(两个字节),l表示long(四个字节)
uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
收发第二套API:
在这里插入图片描述
sendto,recvform等函数多用于UDP协议
在这里插入图片描述

简单聊天室代码示例:

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

int main(int argc,char **argv) {
    int socket_id;
    int cnt=0;
    struct sockaddr_in server_addr;
    struct sockaddr_in client_addr;
    char readBuf[128] = {0};
    char msg[128] = {0};

    memset(&server_addr, 0, sizeof(struct sockaddr_in));
    memset(&client_addr, 0, sizeof(struct sockaddr_in));

    if(argc!=3){
        printf("argument too lease\n");
        exit(-1);
    }

    socket_id = socket(AF_INET, SOCK_STREAM, 0);

    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(atoi(argv[2]));
    inet_aton(argv[1], &server_addr.sin_addr);
    bind(socket_id, (struct sockaddr *)&server_addr, sizeof(server_addr));

    listen(socket_id, 5);
    int clen = sizeof(struct sockaddr_in);

    while (1) {
        int client_id =
            accept(socket_id, (struct sockaddr *)&client_addr, &clen);
        if (client_id != -1) {
            printf("accept client IP is %s\n", inet_ntoa(client_addr.sin_addr));
        }
        cnt++;
        if (fork() == 0) {
            if (fork() == 0) {
                while (1) {
                    memset(msg, 0, sizeof(msg));
                    sprintf(msg,"NO.%d Client",cnt);
                    write(client_id, msg, sizeof(msg));
                    sleep(3);
                }
            }
            while (1) {
                memset(readBuf, 0, sizeof(readBuf));
                int n_read=read(client_id, readBuf, sizeof(readBuf));
                if(n_read>0){
                    printf("read form %s:%s\n", inet_ntoa(client_addr.sin_addr),
                        readBuf);
                }
            }
        }
    }
    close(socket_id);
}

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

int main(int argc,char **argv) {
    int socket_id;
    struct sockaddr_in server_addr;
    char readBuf[128] = {0};
    char msg[128] = {0};

    memset(&server_addr,0,sizeof(struct sockaddr_in));
    if(argc!=3){
        printf("argument too lease\n");
        exit(-1);
    }
    socket_id = socket(AF_INET, SOCK_STREAM, 0);

    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(atoi(argv[2]));
    inet_aton(argv[1],&server_addr.sin_addr);
    
    if(connect(socket_id,(struct sockaddr *)&server_addr,sizeof(struct sockaddr_in))==-1){
        perror("connect");
        exit(-1);
    }
    if(fork()==0){
        while(1){
            memset(msg,0,sizeof(msg));
            printf("input:");
            gets(msg);
            write(socket_id,msg,strlen(msg));
        }
    }
    while(1){
        memset(readBuf,0,sizeof(readBuf));
        int n_read = read(socket_id,readBuf,sizeof(readBuf));
        if(n_read==-1){
            perror("read");
            exit(-1);
        }else if(n_read > 0){
            printf("rec mes form IP %s,%s\n",argv[1],readBuf);
        }
    }

    close(socket_id);

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值