
C 网络编程
发布日期:2021-05-07 20:54:58
浏览次数:26
分类:精选文章
本文共 6091 字,大约阅读时间需要 20 分钟。
套接字与网络编程基础
套接字
套接字是网络编程中的核心概念,它描述了客户端请求到达服务器的标识。套接字包含源IP地址、目标IP地址、源端口号和目标端口号等信息。套接字在TCP/IP协议中起着关键作用,用于实现数据的可靠传输和网络通信。
在TCP/IP协议族中,套接字有三种主要类型:
1. 流套接字(SOCK_STREAM)
流套接字提供面向连接、可靠的数据传输服务。它使用TCP协议,确保数据能够无差错、无重复地按顺序传输。流套接字适用于需要可靠通信的场景,如Web浏览器与服务器之间的通信。
2. 数据报套接字(SOCK_DGRAM)
数据报套接字提供无连接的服务。它使用UDP协议,数据传输速度快,但不保证数据的可靠性和顺序性。数据报套接字适用于对实时性要求较高的场景,如视频会议或在线游戏。
3. 原始套接字(SOCK_RAW)
原始套接字允许程序直接访问网络层和传输层的协议。它常用于检验新协议的实现或操作底层网络协议,如ICMP或IP包的接收和发送。
套接字函数
套接字的创建和操作需要使用一系列函数,这些函数在不同操作系统(如Linux和Windows)下有所不同。
1. 创建套接字
Linux: int socket(int af, int type, int protocol);Windows: SOCKET socket(int af, int type, int protocol);
af
:地址族,通常为AF_INET(IPv4)或AF_INET6(IPv6)。type
:套接字类型,如SOCK_STREAM(流套接字)或SOCK_DGRAM(数据报套接字)。protocol
:协议类型,通常为0或 IPPROTO_TCP(TCP)或 IPPROTO_UDP(UDP)。
2. 绑定套接字
Linux: int bind(int sock, const struct sockaddr *myaddr, socklen_t addrlen);Windows: int bind(SOCKET sock, const struct sockaddr *addr, int addrlen);
绑定套接字使其关联到特定的IP地址和端口。
3. 进入监听状态
Linux: int listen(int sockfd, int backlog);Windows: int listen(SOCKET sock, int backlog);
将套接字置于监听状态,等待客户端连接。
4. 等待客户端连接
Linux: int accept(int sockfd, struct sockaddr *client_addr, socklen_t *len);Windows: SOCKET accept(SOCKET sock, struct sockaddr *addr, int *addrlen);
接受客户端的连接请求,返回新的套接字。
5. 客户端连接服务器
Linux: int connect(int sock_fd, struct sockaddr *serv_addr, int addrlen);Windows: int connect(SOCKET sock, const struct sockaddr *serv_addr, int addrlen);
客户端主动连接到服务器。
接受与发送函数
1. 发送数据
Linux: ssize_t write(int fd, const void *buf, size_t nbytes);Windows: int send(SOCKET sock, const char *buf, int len, int flags);
2. 读取数据
Linux: ssize_t read(int fd, void *buf, size_t nbytes);Windows: int recv(SOCKET sock, char *buf, int len, int flags);
相关结构体
1. struct sockaddr_in
用于设置IP地址和端口信息。
2. struct sockaddr
表示套接字地址,适用于所有地址族。
IP与端口函数
1. inet_pton
将IP地址从“点分十进制”格式转换为二进制整数格式,支持IPv4和IPv6。
2. inet_ntop
将二进制整数格式的IP地址转换为“点分十进制”格式。
3. htons和ntohs
将短整型数从主机字节序转换为网络字节序。
Windows示例代码
服务端代码
#include#include #pragma comment(lib, "ws2_32.lib")#define BUF_SIZE 100int main() { // 初始化Winsock WSADATA wsaData; WSAStartup(MAKEWORD(2, 2), &wsaData); // 创建套接字 SOCKET serverSock = socket(AF_INET, SOCK_STREAM, 0); // 绑定套接字 SOCKADDR_IN sockAddr; memset(&sockAddr, 0, sizeof(sockAddr)); sockAddr.sin_family = PF_INET; sockAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); sockAddr.sin_port = htons(9080); bind(serverSock, (SOCKADDR*)&sockAddr, sizeof(SOCKADDR)); // 进入监听状态 listen(serverSock, 20); // 接受客户端连接 SOCKADDR cltAddr; int nSize = sizeof(cltAddr); char buffer[BUF_SIZE] = {0}; while(1) { SOCKET clientSock = accept(serverSock, (SOCKADDR*)&cltAddr, &nSize); int strLen = recv(clientSock, buffer, BUF_SIZE, 0); printf("Message from client: %s\n", buffer); // 读取用户输入并发送回复 printf("Input a string: "); gets_s(buffer, BUF_SIZE); send(clientSock, buffer, strLen, 0); // 重置缓冲区 memset(buffer, 0, BUF_SIZE); closesocket(clientSock); } // 关闭套接字 closesocket(serverSock); WSACleanup(); return 0;}
客户端代码
#include#include #pragma comment(lib, "ws2_32.lib")#define BUF_SIZE 100int main() { // 初始化Winsock WSADATA wsaData; WSAStartup(MAKEWORD(2, 2), &wsaData); // 创建套接字 SOCKADDR_IN sockAddr; memset(&sockAddr, 0, sizeof(sockAddr)); sockAddr.sin_family = PF_INET; sockAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); sockAddr.sin_port = htons(9080); char bufSend[BUF_SIZE] = {0}; char bufRecv[BUF_SIZE] = {0}; while (1) { // 创建套接字 SOCKET sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); connect(sock, (SOCKADDR*)&sockAddr, sizeof(SOCKADDR)); // 获取用户输入并发送 printf("Input a string:"); gets_s(bufSend, sizeof(bufSend)); send(sock, bufSend, BUF_SIZE, 0); // 接收服务器回复 int recvLen = recv(sock, bufRecv, BUF_SIZE, 0); printf("Message from server: %s\n", bufRecv); // 重置缓冲区 memset(bufSend, 0, sizeof(bufSend)); memset(bufRecv, 0, sizeof(bufRecv)); closesocket(sock); } WSACleanup(); return 0;}
Linux示例代码
服务端代码
#include#include #include #include #include #include #define BUF_SIZE 100int main() { // 创建套接字 int serverSock = socket(AF_INET, SOCK_STREAM, 0); // 绑定套接字 struct sockaddr_in sockAddr; memset(&sockAddr, 0, sizeof(sockAddr)); sockAddr.sin_family = AF_INET; sockAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); sockAddr.sin_port = htons(9080); bind(serverSock, (struct sockaddr*)&sockAddr, sizeof(struct sockaddr)); // 进入监听状态 listen(serverSock, 20); struct sockaddr cltAddr; socklen_t nSize = sizeof(cltAddr); char buffer[BUF_SIZE] = {0}; while(1) { int clientSock = accept(serverSock, (struct sockaddr*)&cltAddr, &nSize); int strLen = read(clientSock, buffer, BUF_SIZE); printf("Message from client: %s\n", buffer); // 读取用户输入并发送回复 printf("Input a string: "); fgets(buffer, sizeof(buffer), stdin); write(clientSock, buffer, strLen); // 重置缓冲区 memset(buffer, 0, BUF_SIZE); close(clientSock); } close(serverSock); return 0;}
客户端代码
#include#include #include #include #include #include #define BUF_SIZE 100int main() { struct sockaddr_in sockAddr; memset(&sockAddr, 0, sizeof(sockAddr)); sockAddr.sin_family = AF_INET; sockAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); sockAddr.sin_port = htons(9080); char bufSend[BUF_SIZE] = {0}; char bufRecv[BUF_SIZE] = {0}; while (1) { // 创建套接字 int sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); connect(sock, (struct sockaddr*)&sockAddr, sizeof(struct sockaddr)); // 获取用户输入并发送 printf("Input a string:"); fgets(bufSend, sizeof(bufSend), stdin); send(sock, bufSend, BUF_SIZE, 0); // 接收服务器回复 int recvLen = recv(sock, bufRecv, BUF_SIZE, 0); printf("Message from server: %s\n", bufRecv); // 重置缓冲区 memset(bufSend, 0, sizeof(bufSend)); memset(bufRecv, 0, sizeof(bufRecv)); close(sock); } return 0;}
发表评论
最新留言
留言是一种美德,欢迎回访!
[***.207.175.100]2025年04月09日 12时57分46秒
关于作者

喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
C语言的数值溢出问题(上)
2019-03-05
8051单片机(STC89C52)以定时器中断模式实现两倒计时器异步计时
2019-03-05
vue项目通过vue.config.js配置文件进行proxy反向代理跨域
2019-03-05
android:使用audiotrack 类播放wav文件
2019-03-05
聊聊我的五一小假期
2019-03-05
数据库三个级别封锁协议
2019-03-05
ACM/NCPC2016 C Card Hand Sorting(upc 3028)
2019-03-05
ubuntu学习笔记-常用文件、命令以及作用(hosts、vim、ssh)
2019-03-05
SLAM学习笔记-求解视觉SLAM问题
2019-03-05
程序员应该知道的97件事
2019-03-05
create-react-app路由的实现原理
2019-03-05
openstack安装(九)网络服务的安装--控制节点
2019-03-05
shell编程(六)语言编码规范之(变量)
2019-03-05
vimscript学习笔记(二)预备知识
2019-03-05
Android数据库
2019-03-05
HTML基础,块级元素/行内元素/行内块元素辨析【2分钟掌握】
2019-03-05
STM8 GPIO模式
2019-03-05
23种设计模式一:单例模式
2019-03-05
Qt中的析构函数
2019-03-05