我正在尝试实现套接字库。一切都做得很好,直到我达到接受功能。我调查了堆栈溢出,我说它不会返回,直到客户端通过这个连接,但如果它不是在blockmode。所以,我想知道:如何改变听到NONBLOCK模式?
这是我的标题:
#ifndef NET_SOCKET_H
#define NET_SOCKET_H
#ifdef __cplusplus
extern "C" {
#endif
#if defined(WIN32) || defined(WINDOWS_XP)
#include <winsock2.h>
#endif
#include <type-of/include/type.h>
#include <unistd.h>
#define NET_SOCK_ALLOCATED 1
typedef struct NetSocket NET_SOCK;
typedef struct sockaddr_in NET_ADDR_IN;
typedef struct sockaddr NET_ADDR;
struct NetSocket {
struct {
B32 sys; // PF_INET or PF_UNIX
B32 data; // SOCK_STREAM or SOCK_DGRAM
B32 mode; // IPPROTO_TCP or IPPROTO_UDP
} from;
#if defined(WIN32) || defined(WINDOWS_XP)
SOCKET sock;
#else
B32 sock;
#endif
B8 * host;
NET_ADDR_IN to;
BIT status;
STATUS(*open)(NET_SOCK * net);
STATUS(*tie)(NET_SOCK * server);
STATUS(*wait)(NET_SOCK * net, B32 max);
STATUS(*join)(NET_SOCK * server, NET_SOCK * client);
STATUS(*in)(NET_SOCK * client);
void (*close)(NET_SOCK * net);
void (*pop)(NET_SOCK * net);
};
NET_SOCK net_sock_std(B8U * host, B32U port);
NET_SOCK * net_sock_push(B8U * host, B32U port);
void net_sock_zero(NET_SOCK * net);
STATUS net_sock_open(NET_SOCK * net);
STATUS net_sock_tie(NET_SOCK * server);
STATUS net_sock_wait(NET_SOCK * net, B32 max);
STATUS net_sock_join(NET_SOCK * server, NET_SOCK * client);
STATUS net_sock_in(NET_SOCK * client);
STATUS net_sock_put(NET_SOCK * net);
void net_sock_close(NET_SOCK * net);
void net_sock_pop(NET_SOCK * net);
void winsock_start();
void winsock_stop();
#ifdef __cplusplus
}
#endif
#endif /* NET_SOCKET_H */
这是我的来源:
#include "net_socket.h"
void net_sock_function(NET_SOCK * net){
if(net){
net->open = net_sock_open;
net->tie = net_sock_tie;
net->wait = net_sock_wait;
net->join = net_sock_join;
net->in = net_sock_in;
net->close = net_sock_close;
net->pop = net_sock_pop;
}
}
NET_SOCK net_sock_std(B8U * host, B32U port){
NET_SOCK net;
net_sock_zero(&net);
if(host)net.host = strdup(host);
if(port)net.to.sin_port = htons(port);
bit_off(&net.status,NET_SOCK_ALLOCATED);
return(net);
}
NET_SOCK * net_sock_push(B8U * host, B32U port){
NET_SOCK * net = malloc(sizeof(NET_SOCK));
net_sock_zero(net);
if(host)net->host = strdup(host);
if(port)net->to.sin_port = htons(port);
bit_on(&net->status,NET_SOCK_ALLOCATED);
return(net);
}
void net_sock_zero(NET_SOCK * net){
if(net){
winsock_start();
net->from.data = SOCK_STREAM;
net->from.mode = IPPROTO_TCP;
if(is_win()){
net->from.sys = AF_INET;
net->to.sin_family = AF_INET;
}
else {
net->from.sys = AF_UNIX;
net->to.sin_family = AF_UNIX;
}
net->sock = -1;
net->host = NULL;
net->to.sin_addr.s_addr = htonl(INADDR_ANY);
net->to.sin_port = 0;
net_sock_function(net);
}
}
STATUS net_sock_open(NET_SOCK * net){
if(!net)return(Off);
if( (net->sock = socket(net->from.sys,net->from.data,net->from.mode)) != -1)return(On);
return(Off);
}
STATUS net_sock_tie(NET_SOCK * server){
if(!server)return(Off);
if(bind(server->sock,(NET_ADDR*)&server->to,sizeof(server->to)) != -1)return(On);
return(Off);
}
STATUS net_sock_wait(NET_SOCK * net, B32 max){
if(!net)return(Off);
if(listen(net->sock,max) != -1)return(On);
return(Off);
}
STATUS net_sock_join(NET_SOCK * server,NET_SOCK * client){
if(!server || !client)return(Off);
B32U clientLen = sizeof(client->to);
while((client->sock = accept(server->sock,(NET_ADDR *)&client->to,&clientLen)) == -1)return(On);
return(Off);
}
STATUS net_sock_in(NET_SOCK * client){
if(!client)return(Off);
if(connect(client->sock,(NET_ADDR *)&client->to,sizeof(client->to)) != -1)return(On);
return(Off);
}
STATUS net_sock_put(NET_SOCK * net){
if(!net)return(Off);
return(Off);
}
void net_sock_close(NET_SOCK * net){
if(is_win())closesocket(net->sock);
else close(net->sock);
}
void net_sock_pop(NET_SOCK * net){
if(net){
if(net->host){
free(net->host);
net->host = NULL;
}
if(bit_is_on(net->status,NET_SOCK_ALLOCATED)){
free(net);
net = NULL;
}
}
}
void winsock_start() {
if (is_win()) {
WORD versionWanted = MAKEWORD(1, 1);
WSADATA wsaData;
WSAStartup(versionWanted, &wsaData);
atexit(winsock_stop);
}
}
void winsock_stop() {
if (is_win()) {
WSACleanup();
}
}
最后我的主要是:
#include "net_socket.h"
void command_line(B32 c, B8 ** v, B8U ** host, B32U * port) {
B32 i = 1;
while (i < c) {
switch (i) {
case 1:
{
*port = atoi(v[i]);
}
break;
case 2:
{
*host = v[i];
}
break;
}
i++;
}
}
int main(int argc, char** argv) {
B8U * host = NULL;
B32U port = 50;
command_line(argc, argv, &host, &port);
NET_SOCK server = net_sock_std(NULL, port);
if (server.open(&server)) {
if (!host) {
NET_SOCK client = net_sock_std("localhost", port);
printf("server openned in %hu\n", server.to.sin_port);
if (client.open(&client)) {
printf("Server client openned in %hu", client.to.sin_port);
}
if (server.tie(&server) && server.wait(&server, 1)){
printf("\nready\n");
}
while (server.join(&server, &client)){ // I can't get in search mode
printf("searching\n");
}
client.pop(&client);
} else {
NET_SOCK client = net_sock_std(host, port);
if (client.open(&client)) {
printf("client openned in %s %hu\n", host, client.to.sin_port);
while (!client.in(&client)) {
printf("trying to connect\n");
}
printf("bye server\n");
}
}
server.close(&server);
}
server.pop(&server);
return (EXIT_SUCCESS);
}
在我的朋友Jeremy的帮助下,我发现:(只是将服务器SOCK设置为关闭)
STATUS net_lock_socket(NET_SOCK * net, STATUS block) {
if (!net || net->sock < 0) return Off;
#if defined(WIN32)
unsigned long mode = block ? 0 : 1;
return (ioctlsocket(net->sock, FIONBIO, &mode) == 0) ? On : Off;
#else
int flags = fcntl(net->sock, F_GETFL, 0);
if (flags == -1) return Off;
flags = block ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK);
return (fcntl(net->sock, F_SETFL, flags) == 0) ? On : Off;
#endif
}
答案 0 :(得分:1)
首先,快速澄清 - 它不会listen()
阻止,而是accept()
。 listen()
只是让操作系统知道您希望该套接字能够在将来接受传入的TCP连接;所以没有理由阻止它。
其次,要使accept()
无阻塞,您需要首先使您在非阻塞时调用accept()
的套接字 - 有关如何执行此操作的信息可用here
完成此操作后,如果检测到传入的TCP连接,则accept()
将返回-1并将errno设置为EWOULDBLOCK
,如果已经没有TCP连接等待它...所以为了知道何时适合在套接字上调用accept()
,你可以在select()调用中的read fd-set中包含套接字。只要有传入的TCP连接存在,并且是时候调用accept()来处理它,accept-socket就会发出准备就绪的信号。