本文主要讲解Socket网络编程。
首先介绍socket,包括TCP和UDP通信过程;然后介绍常用的函数;最后编写client-server例子,并进行测试。
C 语言中的 socket 编程是一种用于在网络上进行通信的编程接口。通过 socket,程序可以在不同的计算机之间进行数据交换,实现网络通信的功能。
创建 Socket:使用 socket() 函数创建一个套接字,指定地址族为 AF_INET,类型为 SOCK_STREAM(表示流式套接字),协议为 IPPROTO_TCP。这一步通常会得到一个套接字描述符。
绑定 Socket:调用 bind() 函数将套接字与服务器所在主机的 IP 地址和端口号绑定。这样服务器就可以监听来自该端口的连接请求。
监听连接请求:使用 listen() 函数开始监听客户端的连接请求,并设置最大连接数。
接受连接:当有客户端发起连接请求时,使用 accept() 函数接受连接,返回一个新的套接字描述符用于与该客户端进行通信。
数据通信:通过新的套接字描述符,使用 send() 和 recv() 函数发送和接收数据。通常在一个循环中进行数据交换,直到通信结束。
关闭连接:通信结束后,关闭新的套接字描述符,释放资源。
创建 Socket:同样使用 socket() 函数创建套接字,地址族为 AF_INET,类型为 SOCK_STREAM,协议为 IPPROTO_TCP。
连接服务器:使用 connect() 函数向服务器发起连接请求,指定服务器的 IP 地址和端口号。
数据通信:连接建立后,使用 send() 和 recv() 函数发送和接收数据,通常也是在一个循环中进行数据交换,直到通信结束。
关闭连接:通信结束后,关闭套接字描述符,释放资源。
创建 Socket:调用socket()函数创建一个套接字,指定地址族为AF_INET,类型为SOCK_DGRAM(数据报套接字),协议为IPPROTO_UDP。这一步通常会得到一个套接字描述符。
绑定 Socket:使用bind()函数将套接字与服务器所在主机的IP地址和端口号绑定。这样服务器就可以监听来自该端口的数据报。
数据通信:通过绑定的套接字描述符,使用sendto()和recvfrom()函数发送和接收数据报。UDP是无连接的协议,因此每次发送数据时都需要指定目标的IP地址和端口号。
关闭连接:通信结束后,关闭套接字描述符,释放资源。
创建 Socket:同样使用socket()函数创建套接字,地址族为AF_INET,类型为SOCK_DGRAM,协议为IPPROTO_UDP。
数据通信:通过创建的套接字描述符,使用sendto()和recvfrom()函数发送和接收数据报。UDP是无连接的协议,因此每次发送数据时都需要指定目标的IP地址和端口号。
关闭连接:通信结束后,关闭套接字描述符,释放资源。
创建一个新的套接字,返回一个 int 类型的套接字文件描述符,用于后续的网络连接操作。
#include
int socket(int domain, int type, int protocol);
将套接字与一个本地 IP:Port 绑定。通常用于服务端,以便在本地监听网络连接
#include
int bind(int socket, struct sockaddr *addr, socklen_t addrlen);
开始监听来自远程主机的连接请求。通常用于服务器端,在套接字上等待来自客户端的连接请求。
#include
int listen(int socket, int backlog);
建立与远程主机的连接。通常用于客户端,以便连接到远程服务器
#include
int connect(int socket, struct sockaddr *serv_addr, socklen_t addrlen);
接受一个连接请求,返回一个新的、表示客户端的 Socket 文件描述符,作为服务端和客户端之间发送与接收操作的句柄。通常用于服务器端,用于接收客户端的连接请求。
#include
int accept(int sock, struct sockaddr *addr, socklen_t *addrlen);
关闭套接字连接。
#include
int close(int fildes);
从套接字接收数据
#include
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
向套接字发送数据。
#include
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
#include
ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
#include
ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
struct msghdr {
/* 指定接收或发送数据的对端地址,可以为 NULL 或 0,表示不需要使用对端地址。*/
void *msg_name; /* optional address */
socklen_t msg_namelen; /* size of address */
/* 指定接收或发送数据的缓冲区和缓冲区大小,可以使用多个缓冲区同时接收或发送数据。*/
struct iovec *msg_iov; /* scatter/gather array */
size_t msg_iovlen; /* # elements in msg_iov */
/* 指定一些附加的控制信息,可以为 NULL 或 0。*/
void *msg_control; /* ancillary data, see below */
size_t msg_controllen; /* ancillary data buffer len */
/* 指定函数的行为,例如是否需要接收带外数据等。*/
int msg_flags; /* flags on received message */
};
设置socket选项值
#include
int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);
#include
#include
#include
#include
#include
#include
#define PORT 8888
#define MAXLINE 1024
int main() {
int sockfd, connfd;
char buffer[MAXLINE];
struct sockaddr_in servaddr, cli;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
// 创建TCP套接字
if (sockfd == -1) {
printf("socket creation failed");
return EXIT_FAILURE;
}
// 设置服务器地址结构
servaddr.sin_family = AF_INET; // IPv4
servaddr.sin_addr.s_addr = INADDR_ANY;
servaddr.sin_port = htons(PORT);
// 绑定服务器套接字
if (bind(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) != 0) {
printf("socket bind failed");
return EXIT_FAILURE;
}
// 监听连接
if (listen(sockfd, 5) != 0) {
printf("listen failed");
return EXIT_FAILURE;
}
socklen_t len = sizeof(cli);
// 接受连接
connfd = accept(sockfd, (struct sockaddr*)&cli, &len);
if (connfd < 0) {
printf("server accept failed");
return EXIT_FAILURE;
}
// 读取客户端消息
ssize_t num = recv(connfd, buffer, sizeof(buffer),0);
if (num < 0){
printf("read data from client fail, num=%ld\n", num);
return EXIT_FAILURE;
}
printf("Client message: %s, size: %ld\n", buffer, num);
char * data = "hello world";
// 发送消息给客户端
num = send(connfd, data, strlen(data),0);
if (num < 0){
printf("write data to client fail, num=%ld\n", num);
return EXIT_FAILURE;
}
// 关闭连接
close(sockfd);
return 0;
}
#include
#include
#include
#include
#include
#include
#define PORT 8888
#define MAXLINE 1024
int main() {
int sockfd;
char buffer[MAXLINE];
struct sockaddr_in servaddr;
// 创建TCP套接字
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1) {
printf("socket creation failed\n");
return EXIT_FAILURE;
}
// 设置服务器地址结构
servaddr.sin_family = AF_INET; // IPv4
servaddr.sin_port = htons(PORT);
servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
// 连接服务器
if (connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) != 0 ) {
printf("connection with server failed\n");
return EXIT_FAILURE;
}
char *data = "client send data";
// 发送消息给服务器
ssize_t num = send(sockfd, data, strlen(data),0);
if (num < 0 )
{
printf("write data to server fail\n");
return EXIT_FAILURE;
}
// 读取服务器响应
num = recv(sockfd, buffer, sizeof(buffer),0);
if (num < 0 )
{
printf("read data from client fail\n");
return EXIT_FAILURE;
}
printf("Server response: %s\n", buffer);
// 关闭连接
close(sockfd);
return 0;
}