38、C语言中的网络编程
大约 4 分钟C语言基础程序程序厨
基本概念
网络编程的核心概念包括IP地址和端口号:
- IP地址用于唯一标识网络上的设备。
- 端口号则用于标识设备上的特定服务或应用程序。
套接字
在C语言中,都是使用套接字进行网络编程,它涉及以下几个关键步骤:
- 创建套接字:使用
socket()
函数创建一个套接字。 - 绑定地址:使用
bind()
函数将套接字与特定的IP地址和端口号绑定。 - 监听连接:使用
listen()
函数将套接字设置为监听模式,等待客户端连接。 - 接受连接:使用
accept()
函数接受客户端的连接请求,创建一个新的套接字用于与客户端通信。 - 读写数据:使用
recv()
和send()
函数在套接字之间读写数据。 - 关闭套接字:使用
close()
函数关闭套接字。
示例代码(TCP服务器):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#define PORT 8080
#define MAXLINE 1024
int main() {
int sockfd, connfd;
struct sockaddr_in servaddr, cliaddr;
socklen_t len = sizeof(cliaddr);
// 创建套接字
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
perror("Socket creation failed");
exit(EXIT_FAILURE);
}
// 设置地址结构
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(PORT);
// 绑定套接字
if (bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) {
perror("Bind failed");
exit(EXIT_FAILURE);
}
// 监听连接
if (listen(sockfd, 5) < 0) {
perror("Listen failed");
exit(EXIT_FAILURE);
}
// 接受连接
connfd = accept(sockfd, (struct sockaddr *)&cliaddr, &len);
if (connfd < 0) {
perror("Accept failed");
exit(EXIT_FAILURE);
}
// 读取客户端数据
char buffer[MAXLINE];
int n = recv(connfd, buffer, MAXLINE - 1, 0);
if (n < 0) {
perror("Recv failed");
exit(EXIT_FAILURE);
}
buffer[n] = '\0';
printf("Client: %s\n", buffer);
// 向客户端发送数据
const char *msg = "Hello from server";
send(connfd, msg, strlen(msg), 0);
// 关闭套接字
close(connfd);
close(sockfd);
return 0;
}
TCP/IP协议与套接字通信
TCP/IP
协议是互联网上最常用的通信协议。
TCP
(传输控制协议)是面向连接的可靠的传输协议,利用TCP协议进行通信时,首先要建立通信双方的连接。一旦连接建立完成,就可以进行通信。
**TCP
**还提供了数据确认和数据重传的机制,保证了发送的数据一定能到达通信的对方,这就是为什么说TCP是可靠传输的原因。
基于TCP
的套接字编程的服务器端程序流程如下:
- 创建套接字。
- 将创建的套接字绑定到本地的地址和端口上。
- 设置套接字的状态为监听状态,准备接受客户端的连接请求。
- 接受请求,同时返回得到一个用于连接的新套接字。
- 使用这个新套接字进行通信(通信函数使用
send/recv
)。 - 通信完毕,释放套接字资源(
closesocket
)。
基于TCP的套接字编程的客户端程序流程如下:
- 创建套接字。
- 向服务器发出连接请求(
connect
)。 - 连接后,与服务器进行通信操作(
send/recv
)。 - 释放套接字资源(
closesocket
)。
示例代码(TCP客户端):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#define PORT 8080
int main() {
int sock;
struct sockaddr_in serv_addr;
const char *message = "Hello from client";
char buffer[1024] = {0};
// 创建套接字
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("\nSocket creation error\n");
return -1;
}
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT);
// 转换地址
if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) {
printf("\nInvalid address\n");
return -1;
}
// 连接服务器
if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
printf("\nConnection failed\n");
return -1;
}
send(sock, message, strlen(message), 0);
printf("Hello message sent\n");
read(sock, buffer, 1024);
printf("Message from server: %s\n", buffer);
close(sock);
return 0;
}
UDP协议与广播/多播
UDP(用户数据报协议)是无连接的不可靠的传输协议。采用UDP进行通信时,不需要建立连接,可以直接向一个IP地址发送数据,但是不能保证对方能收到。
UDP协议支持广播和多播。广播是指将数据包发送到网络上的所有设备,而多播则是将数据包发送到网络上的一个特定子集的设备。
UDP广播示例代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
int main() {
int sock;
struct sockaddr_in broadcastAddr;
const char *message = "Hello from UDP broadcast";
char buffer[1024] = {0};
// 创建套接字
if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("Socket creation failed");
exit(EXIT_FAILURE);
}
int broadcastEnable = 1;
if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &broadcastEnable, sizeof(broadcastEnable)) < 0) {
perror("Setsockopt for broadcast failed");
close(sock);
exit(EXIT_FAILURE);
}
broadcastAddr.sin_family = AF_INET;
broadcastAddr.sin_port = htons(8080);
broadcastAddr.sin_addr.s_addr = inet_addr("255.255.255.255"); // 广播地址
// 发送广播消息
if (sendto(sock, message, strlen(message), 0, (struct sockaddr *)&broadcastAddr, sizeof(broadcastAddr)) < 0) {
perror("Sendto failed");
close(sock);
exit(EXIT_FAILURE);
}
close(sock);
return 0;
}
练习
- 利用
socket
,创建TCP
的server
,并编写client
程序,与server
通信,client
向server
发送Hello,World
,server
向client
返回Hello,Client
。
