1-UNIX网络编程-Socket套接字编程简介

2022-07-27 15:41:08 浏览数 (1)

触发学习UNIX网络编程的动力在于前段时间需要开发一个接入服务,需要考虑比较高的并发处理能力,且尽量少占用的机器资源,选用了JAVA的Netty框架,学习过程产生不少疑问,限于基础知识太薄弱无法理解原理,所以开始关注UNIX编程。

学习资料是这本书,书有砖头那么大,知识点非常多,分几个小章节记录汇总。这个章节作为开篇,记录最基础的API使用指引。

有C语言基础都可以看得懂的Server和Client端代

Server端代码

代码语言:javascript复制
#include <stdio.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>

#define MAXLINE     4096
#define LISTENQ     1024

int main(int argc , char **argv ){
    int                 listenfd, connfd, n;
    char                buff[MAXLINE 1];
    struct sockaddr_in  servaddr;
    // socket
    listenfd = socket(AF_INET, SOCK_STREAM, 0);
    bzero(&servaddr,sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(13);
    // bind
    bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
    // listen
    listen(listenfd,LISTENQ);
    for(;;){
        connfd = accept(listenfd,NULL,NULL);
        while( ( n= read(connfd,buff,MAXLINE)) > 0 ){
            printf("receive message from client. message = %s",buff);
            write(connfd,buff,strlen(buff));
            bzero(&buff,sizeof(buff));
        }
        close(connfd);
    }
}

Client端代码

代码语言:javascript复制
#include <stdio.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#define MAXLINE     4096
#define LISTENQ     1024

int
main(int argc , char **argv ){
    int                 sockfd, n;
    char                sendline[MAXLINE 1] ,recvline[MAXLINE 1];
    struct sockaddr_in  servaddr;
    // socket
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    bzero(&servaddr,sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(13);
    inet_pton(AF_INET,"127.0.0.1",&servaddr.sin_addr);
    // connect
    connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
    
    while( fgets(sendline,MAXLINE,stdin) != NULL ){
        write(sockfd,sendline,strlen(sendline));
        bzero(&recvline,sizeof(recvline));
        if( (n = read(sockfd,recvline,MAXLINE) ) > 0 ){
            recvline[n] = 0 ;
            printf("receive message from server. message = %s",recvline);
            // fputs(recvline,stdout);
        }
        bzero(&sendline,sizeof(sendline));
    }
    close(sockfd);
    exit(0);
}

程序运行示例

这是一个简单的回射程序,不管客户端发送什么消息,服务器端接受到消息之后原样返回给客户端。不包含任何错误判断和错误处理。

关键函数注解

代码语言:javascript复制
1、socket函数
int socket( int family , int type , int protocol );
    创建一个套接字文件,返回套接字文件描述符
[family]
    指定协议簇 : AF_INET(IPv4) AF_INET6(IPv6) 
    AF_LOCAL(UNIX协议) AF_ROUTE(路由套接字) AF_KEY(秘钥套接字)
[type]
    指定套接字类型 : SOCK_STREAM(字节流套接字)、
    SOCK_DGRAM(数据报套接字)、SOCK_SEQPACKET(有序分组套接字)、
    ROCK_RAW(原始套接字)
[protocol]
     指定协议类型:IPPROTO_TCP(TCP传输协议)、
     IPPROTO_UDP(UDP传输协议)、IPPROTO_SCTP(STCP传输协议),
     设置为0可以表示选择给定family和type组合的系统默认值。通常设置为0。
代码语言:javascript复制
2、bind函数
int bind(int sockfd , const struct sockaddr *myaddr , 
socklen_t addrlen);
    把一个本地协议地址赋予一个套接字
[sockfd]
    socket函数返回的套接字描述符
[myaddr]
    是指向本地IP地址的通用套接字结构
[addrlen]
    特定套接字结构的长度(IPv4、IPv6、Unix域、数据链路、存储等)
代码语言:javascript复制
3、listen函数
int listen( int sockfd , int backlog );
    把一个本地协议地址赋予一个套接字,把套件字变更为被动连接。
[sockfd]
    socket指示内核接受指向该套接字的连接请求。
[backlog]
    未完成三次握手的请求   已完成三次握手的请求总和。是一个大约值。
代码语言:javascript复制
4、accept函数
int accept( int sockfd , struct sockaddr *cliaddr , 
scoklen_t *addrlen );
    从已完成连接队列队头返回下一个已完成连接,如果丢列为空,
    进程阻塞进入睡眠。
[sockfd]
    socket等待接受连接的侦听套接字。
[cliaddr]
    客户端协议地址。如果不关注客户端的地址,可以设置为NULL。
[addrlen]
    客户端协议地址的端口号。如果不关注,可以设置为NULL。
代码语言:javascript复制
5、connect函数
int connect( int sockfd , const struct sockaddr * servaddr , 
socklen_t addrlen );
     TCP客户端发起跟服务器的连接。
[sockfd]
    由socket函数创建的套接字连接
[servaddr]
    包含服务器IP地址和端口号的套接字地址结构
[addrlen]
     套接字地址结构的大小。
代码语言:javascript复制
bzero       字节操纵函数,用于把目的结构体中指定数目的字节置为0
            类似于memset函数,但是比memset少一个容易出BUG的参数
            在C语言里,对一块刚申请的内存先清零再使用是必须的
htonlhtons 字节排序函数,
            htonl是对32位的IPv4地址做转换
            htons是对16为的端口号做转换
            由机器字节序转变为网络字节序,网际协议使用大端字节序来表示
            字符,而机器则是不同操作系统使用不同的字节序
read        从连接套接字中读取指定长度的内容
write       往连接套接字中写取指定长度的内容
inet_pton   把字符串格式的IP地址,转成相应协议族的数值格式
            另外一个配套的函数是inet_ntop,作用相反
fgets       函数,从标准输入中读取指定长度字符串,有点像scanf

基础知识补齐

1、Socket在OSI(开放系统互联)模型——7层网络模型中的位置

Socket就像一个插头,联通应用层中的应用与网络设备,应用要提供网络服务,或者需要网络服务都得通过Socket的API进行。

2、Socket API的数据流

下周文章提纲

1、C语言错误处理

2、项目文件组织与编写Makefile

3、完成server和client中其他函数的包裹

0 人点赞