龙空技术网

基于Linux下C语言的Socket网络编程

Hu先生Linux后台开发 335

前言:

今天各位老铁们对“c语言socket文件传输”都比较关注,看官们都想要了解一些“c语言socket文件传输”的相关知识。那么小编同时在网摘上网罗了一些有关“c语言socket文件传输””的相关内容,希望你们能喜欢,看官们快快来了解一下吧!

基于Linux下C语言的Socket网络编程

网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket。

Socket被广泛用作网络通信,它几乎支持所有的编程语言,各种语言对于Socket操作流程也比较类似。 服务端程序的创建流程为创建socket——绑定端口号——监听——接受连接——读和写; 客户端程序的创建流程为创建socket——通过IP和端口连接服务端——读和写。 [TOC]

服务端1. 创建Socket

包含头文件: #include <sys/socket.h> #include <sys/types.h> 函数原型:int socket(int domain, int type, int protocol); socket函数里有三个参数。 domain选择通信协议族,常用的有以下几种。

Name Purpose

AF_UNIX, AF_LOCAL Local communication

AF_INET(常用) IPv4 Internet protocols

AF_INET6 IPv6 Internet protocols

type指定Socket类型,常用以下几种。

Name Purpose

SOCK_STREAM 流式套接字(TCP协议)

SOCK_DGRAM 数据报式套接字(UDP协议)

protocol指定协议,常用以下几种

NAME Purpose

IPPROTO_TCP TCP传输协议

IPPROTO_UDP UDP传输协议

IPPROTO_STCP STCP传输协议

IPPROTO_TIPC TIPC传输协议

type和protocol不可以随意组合,当第三个参数type为 0自动选择第二个参数对应的默认协议

Socket如果创建成功,则返回一个描述该网络通信端点的文件描述符,操作系统会自动分配当前最小可用的文件描述符。

示例代码

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

2. 绑定端口号和IP地址

包含头文件:

#include <sys/socket.h>

#include <sys/types.h>

函数原型:int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

bind()函数把地址族中的特定地址赋给socket。

sockfdsocket描述字,通过socket创建,标识唯一一个服务端描述字。

sockaddr结构体,通过初始化sockaddr_in结构体然后进行强制类型转化。示例代码如下:

struct sockaddr_in *server_socket = (struct sockaddr_in *)malloc(sizeof(struct sockaddr_in));memset(server_socket, 0, sizeof (struct sockaddr_in)); // 清空sockaddr_in 结构体server_socket->sin_addr.s_addr = htonl(INADDR_ANY); // 任意IP地址server_socket->sin_family = AF_INET; // 使用IPv4协议族server_socket->sin_port = htons(PORT); // 端口号

addrlen为sockaddr的长度。

bind示例代码如下

bind(sockfd, (struct sockaddr *)server_socket, sizeof (struct sockaddr));

3. 连接和监听

包含头文件:

#include <sys/socket.h>

#include <sys/types.h>

函数原型int listen(int sockfd, int backlog);

sockfd为服务端建立socket的文件描述符

backlog为对应socket可以排队的最大连接数

服务端调用listen()函数监听socket,当客户端通过connect()函数连接服务端,发送连接请求时,listen()就会监听到这个请求。

4. 接受客户端连接

包含头文件:

#include <sys/socket.h>

#include <sys/types.h>

函数原型int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

sockfd为服务端打开的socket描述字

addr用于保存连接的客户端的IP地址和端口号,其内容与sockaddr结构体类似。

addrlen是接受地址的长度。

accept()函数如果执行成功,则返回一个由内核生成的全新的套接字,用于和新客户端之间通信。

5. 读和写

包含头文件:

#include <unistd.h>

函数原型:ssize_t read(int fd, void *buf, size_t count);

函数原型:ssize_t write(int fd, const void *buf, size_t count);

当socket打开网络描述字后,程序可以像读写文件一样向网络描述字读或者写,对应接受和发送数据。

客户端1. 创建socket

过程同服务端,socket返回的套接字描述符将直接用于和对端通信。

2. 连接服务器

函数原型int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); sockfd为客户端建立socket的文件描述符 addr为sockaddr结构体保存的服务端的IP地址和端口号,以及协议类型,例如:

struct sockaddr_in *server_addr = (struct sockaddr_in *)malloc(sizeof (struct sockaddr_in)); memset(server_addr, 0, sizeof (struct sockaddr_in)); server_addr->sin_family = AF_INET; // 使用IPv4协议族server_addr->sin_port = htons(port); // port为服务器绑定的端口号inet_pton(AF_INET, "xxx.xxx.xxx.xxx", &server_addr->sin_addr); // 服务端的IP地址

客户端发起tcp连接请求,服务端监听到请求并接受请求后,TCP连接建立即可以开始传输文件。(如果使用UDP协议有些许区别,暂时不做讨论。)

3.发送数据

连接建立后,客户端通过write()和write()函数向打开的sockfd发送或接受数据

代码示例Server

#include <stdio.h>#include <sys/socket.h>#include <sys/types.h>#include <sys/select.h>#include <arpa/inet.h>#include <netinet/in.h>#include <unistd.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#define PORT 8000int main(){    // 创建socket     int sockfd = socket(AF_INET, SOCK_STREAM, 0);    // 申请服务端和客户端地址结构体空间,客户端地址用于保存新连接的地址端口信息    struct sockaddr_in *server_socket = (struct sockaddr_in *)malloc(sizeof(struct sockaddr_in));    struct sockaddr_in *client_socket = (struct sockaddr_in *)malloc(sizeof(struct sockaddr_in));    socklen_t client_address_len;    memset(server_socket, 0, sizeof (struct sockaddr_in));    memset(client_socket, 0, sizeof (struct sockaddr_in));    server_socket->sin_addr.s_addr = htonl(INADDR_ANY);    server_socket->sin_family = AF_INET;    server_socket->sin_port = htons(PORT);    // 绑定    bind(sockfd, (struct sockaddr *)server_socket, sizeof (struct sockaddr));    // 监听    listen(sockfd, 20);    // 接受    int connect_fd = accept(sockfd, (struct sockaddr *)client_socket, &client_address_len);    char buf[] = "Hello Wrold!";    // 发送    while(write(connect_fd, buf, strlen(buf)))    {        printf("send msg: %s\n", buf);        sleep(1);    }    return 0;}
Client
#include <stdio.h>#include <sys/socket.h>#include <sys/types.h>#include <sys/select.h>#include <arpa/inet.h>#include <netinet/in.h>#include <unistd.h>#include <stdio.h>#include <stdlib.h>#include <string.h>int main(){    // 创建socket    int sockfd = socket(AF_INET, SOCK_STREAM, 0);    // 准备地址结构体    struct sockaddr_in *server_addr = (struct sockaddr_in *)malloc(sizeof (struct sockaddr_in));    memset(server_addr, 0, sizeof (struct sockaddr_in));    server_addr->sin_family = AF_INET;    server_addr->sin_port = htons(8000);    inet_pton(AF_INET, "127.0.0.1", &server_addr->sin_addr);    // 连接    connect(sockfd, (struct sockaddr *)server_addr, sizeof (struct sockaddr)); // sockaddr_in强制转换成sockaddr    char buf[1024] = "";    // 读取    while(read(sockfd, buf, 1024))    {        printf("recv msg: %s\n", buf);        memset(buf, 0, 1024);    }    return 0;}
最后小编建了一个c/c++ Linux的学习技术交流群,会不定期的分享一些视频学习资料:主要有C/C++,Linux,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK技术,面试技巧方面的资料。

感兴趣的朋友可以后台私信【架构】获取

标签: #c语言socket文件传输