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;}
上一篇:C socket编程--套接字函数
下一篇:C 语言拼接字符串

发表评论

最新留言

留言是一种美德,欢迎回访!
[***.207.175.100]2025年04月09日 12时57分46秒