什么是CentOS socket
在CentOS操作系统中,Socket是一种用于进程间通信(IPC)的机制,它允许不同主机上的进程通过网络进行通信,Socket可以看作是一种特殊的文件描述符,它提供了一种标准的文件I/O操作接口,让应用程序能够方便地进行网络数据传输。
工作原理
1、服务端:首先通过socket()
函数创建一个套接字,然后使用bind()
函数将该套接字与本地地址和端口号绑定,接着调用listen()
函数使套接字进入监听状态,等待客户端的连接请求,当有客户端发起连接时,accept()
函数会接受连接并返回一个新的套接字,用于与客户端进行数据交互。
2、客户端:同样先通过socket()
函数创建一个套接字,然后使用connect()
函数向服务端的地址和端口发起连接请求,连接成功后,客户端就可以通过套接字与服务端进行数据的发送和接收。
3、数据传输:建立连接后,服务端和客户端可以通过send()
或recv()
函数进行数据的发送和接收,实现双向的数据交换。
4、关闭连接:当通信完成后,双方需要调用close()
函数关闭套接字,释放资源。
常用函数及参数
1、socket():创建一个新的套接字,其原型为int socket(int domain, int type, int protocol)
,其中domain
指定协议族,如AF_INET
表示IPv4;type
指定套接字类型,如SOCK_STREAM
表示流式套接字,SOCK_DGRAM
表示数据报套接字;protocol
通常设置为0,表示使用默认协议。
2、bind():将套接字与指定的IP地址和端口号绑定,原型为int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
,其中sockfd
是套接字描述符,addr
是指向包含IP地址和端口号的结构体的指针,addrlen
是该结构体的大小。
3、listen():使套接字进入监听状态,等待客户端的连接请求,原型为int listen(int sockfd, int backlog)
,其中sockfd
是套接字描述符,backlog
指定了等待连接的最大队列长度。
4、accept():接受客户端的连接请求,返回一个新的套接字描述符,原型为int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
,其中sockfd
是监听套接字描述符,addr
和addrlen
用于获取客户端的IP地址和端口号等信息。
5、connect():主动发起到服务器的连接,原型为int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
,其中sockfd
是套接字描述符,addr
是指向包含服务器IP地址和端口号的结构体的指针,addrlen
是该结构体的大小。
6、send():通过套接字发送数据,原型为ssize_t send(int sockfd, const void *buf, size_t len, int flags)
,其中sockfd
是套接字描述符,buf
是要发送的数据缓冲区,len
是数据的长度,flags
用于指定发送选项。
7、recv():通过套接字接收数据,原型为ssize_t recv(int sockfd, void *buf, size_t len, int flags)
,其中sockfd
是套接字描述符,buf
是用于存储接收数据的缓冲区,len
是缓冲区的长度,flags
用于指定接收选项。
8、close():关闭套接字,原型为int close(int sockfd)
,其中sockfd
是套接字描述符。
示例代码
以下是一个简单的基于TCP的CentOS socket编程示例,实现了一个客户端和服务端的基本通信:
服务端代码:
```c++
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#define PORT 8080
int main() {
int server_fd, new_socket;
struct sockaddr_in address;
int opt = 1;
int addrlen = sizeof(address);
char buffer[1024] = {0};
char *hello = "Hello from server";
// 创建socket文件描述符
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
perror("socket failed");
exit(EXIT_FAILURE);
}
// 强制附加套接字到端口8080
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {
perror("setsockopt");
exit(EXIT_FAILURE);
}
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(PORT);
// 将套接字绑定到上述端口
if (bind(server_fd, (struct sockaddr *)&address, sizeof(address))<0) {
perror("bind failed");
exit(EXIT_FAILURE);
}
if (listen(server_fd, 3) < 0) {
perror("listen");
exit(EXIT_FAILURE);
}
if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen))<0) {
perror("accept");
exit(EXIT_FAILURE);
}
read(new_socket , buffer, 1024);
printf("%s
",buffer );
send(new_socket , hello , strlen(hello) , 0 );
printf("Hello message sent
");
close(server_fd);
return 0;
客户端代码: ```c++ #include <stdio.h> #include <sys/socket.h> #include <arpa/inet.h> #include <unistd.h> #include <string.h> #define PORT 8080 int main() { struct sockaddr_in serv_addr; int sock = 0; char *hello = "Hello from client"; char buffer[1024] = {0}; if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { printf(" Socket creation error "); 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(" Invalid address/ Address not supported "); return 1; } if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) { printf(" Connection Failed "); return 1; } send(sock , hello , strlen(hello) , 0 ); printf("Hello message sent "); int valread = read( sock , buffer, 1024); printf("%s ",buffer ); close(sock); return 0; }
FAQs
1、Q: CentOS socket编程中,如何选择合适的协议族和套接字类型?
A: 选择协议族主要取决于应用的网络环境,如果是在同一台主机上进行进程间通信,可以选择AF_UNIX
协议族;如果是在不同主机之间进行通信,则根据网络层协议选择AF_INET
(IPv4)或AF_INET6
(IPv6),套接字类型的选择则根据应用的需求来决定,如果需要可靠的、面向连接的通信,如文件传输、邮件等,应选择流式套接字(SOCK_STREAM);如果对实时性要求较高,且能容忍一定的数据丢失,如视频直播、实时聊天等,可以选择数据报套接字(SOCK_DGRAM)。
2、Q: CentOS socket编程中,如何处理多个客户端的并发连接?
A: 可以使用多线程或多进程的方式来处理多个客户端的并发连接,对于每个客户端的连接请求,服务端在接受连接后,可以创建一个新的线程或进程来专门处理该客户端的数据交互,这样主线程或主进程就可以继续监听其他客户端的连接请求,从而实现并发处理。