导航:首页 > 编程系统 > linuxconnect

linuxconnect

发布时间:2022-09-18 22:58:25

linux 怎样实现非阻塞connect

1. 设置socket
int oldOption = fcntl(sockfd, F_GETFL);
int newOption = oldOption | O_NONBLOCK;
//设置sockfd非阻塞
fcntl(sockfd, F_SETFL, newOption);12345

2. 执行connect
如果返回0,表示连接成功,这种情况一般在本机上连接时会出现(否则怎么可能那么快)
否则,查看error是否等于EINPROGRESS(表明正在进行连接中),如果不等于,则连接失败
int ret = connect(sockfd, (struct sockaddr*)&addr, sizeof(addr));
if(ret == 0)
{
//连接成功
fcntl(sockfd, F_SETFL, oldOption);
return sockfd;
}
else if(errno != EINPROGRESS)
{
//连接没有立即返回,此时errno若不是EINPROGRESS,表明错误
perror("connect error != EINPROGRESS");
return -1;
}12345678910111213141516

3. 使用select,如果没用过select可以去看看
用select对socket的读写进行监听
那么监听结果有四种可能
1. 可写(当连接成功后,sockfd就会处于可写状态,此时表示连接成功)
2. 可读可写(在出错后,sockfd会处于可读可写状态,但有一种特殊情况见第三条)
3. 可读可写(我们可以想象,在我们connect执行完到select开始监听的这段时间内,
如果连接已经成功,并且服务端发送了数据,那么此时sockfd就是可读可写的,
因此我们需要对这种情况特殊判断)
说白了,在可读可写时,我们需要甄别此时是否已经连接成功,我们采用这种方案:
再次执行connect,然后查看error是否等于EISCONN(表示已经连接到该套接字)。
4. 错误

if(FD_ISSET(sockfd, &writeFds))
{
//可读可写有两种可能,一是连接错误,二是在连接后服务端已有数据传来
if(FD_ISSET(sockfd, &readFds))
{
if(connect(sockfd, (struct sockaddr*)&addr, sizeof(addr)) != 0)
{
int error=0;
socklen_t length = sizeof(errno);
//调用getsockopt来获取并清除sockfd上的错误.
if(getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &length) < 0)
{
printf("get socket option failed\n");
close(sockfd);
return -1;
}
if(error != EISCONN)
{
perror("connect error != EISCONN");
close(sockfd);
return -1;
}
}
}
//此时已排除所有错误可能,表明连接成功
fcntl(sockfd, F_SETFL, oldOption);
return sockfd;
}0

4. 恢复socket
因为我们只是需要将连接操作变为非阻塞,并不包括读写等,所以我们吃醋要将socket重新设置。
fcntl(sockfd, F_SETFL, oldOption);关于Linux命令的介绍,看看《linux就该这么学》,具体关于这一章地址3w(dot)linuxprobe/chapter-02(dot)html

Ⅱ linux connect error:

你用的是tcp协议吧?tcp协议通信需要三次握手,你需要建立两个程序:服务端和客户端。服务端要绑定ip地址并进行端口监听,客户端要连接服务器的端口。

Ⅲ LINUX网络编程 connect被拒绝

一般经过创建套接字socket()绑定bind()以及listen()之后, 就可以调用 accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);判断是否有客户端回发起链接答请求, 不用accept()改用select()可以吗,select(int maxfdp,fd_set *readfds,fd_set *writefds,fd_set *errorfds,struct timeval *timeout) 中哪个参数跟客户端有关?

Ⅳ linux服务器和网络不通(除了ping本机能ping通其他都是connect(网络不可达))

因为你ping的是外网,这说明你没连上外网。其实你这个情况有两种情况,一是虚拟机,虚拟上网很简单,可以是nat模式,然后再把linux的网址配置成DHCP就是动态分配网址,好了很简单可以上网了(如果linux不会配置成DHCP,你可以看看《linux就该这么学》这本书,或者直接网络搜,如何配置网卡也行,看看你的linux像红帽系列的);另一种情况是物理机,如果是笔记本的话,有无线网卡,装机的时候一般网卡驱动都有了,除非你的网卡是假的,然后右上角有一个wifi的标志,windows一样输入密码,如果是台式机就插个网线吧,网卡驱动也都装上了吧,直接上就可以了吧

Ⅳ linux connect失败 错误码22 哪位能解释下吗

错误码22是错误的参数:

#define EINVAL 22 /* Invalid argument */

函数输入有问题

Ⅵ linux下socket编程中connect()函数

关闭后,要再次调用
socket(AF_INET,SOCK_STREAM,0);
来创建socket, 才可以

补充:Linux是一套免费使用和自由传播的类回Unix操作系统,是一个基于答POSIX和UNIX的多用户、多任务、支持多线程和多CPU的操作系统。它能运行主要的UNIX工具软件、应用程序和网络协议。它支持32位和64位硬件。Linux继承了Unix以网络为核心的设计思想,是一个性能稳定的多用户网络操作系统。


Ⅶ C语言Linux系统下TCP编程,connect 错误

你的client有问题,连接之前没有指定server的ip。
你只指定了端内口。
struct sockaddr_in servaddr;
bzero(&servaddr,sizeof(servaddr));
servaddr.sin_family=AF_INET;
servaddr.sin_port=htons(HELLO_WORLD_SERVER_PORT);
servaddr.sin_addr.s_addr=inet_addr(serverip);//加上server的ip即可容

Ⅷ Linux 网络编程时connect()返回-1,为什么会造成这种情况求大神指教。

connect()返回-1的情况很多,要打印errno和详细的错误信息来看。

在返回-1错误的地方增加下面这行代码,然后看看控制台的输出信息:

perror("Err");

然后根据错误信息到网上去搜索相应的解决方案。

Ⅸ linux服务器如何感知有connect请求

1、sys_connect

对于客户端来说,当创建了一个套接字后,就可以连接它了。
case SYS_CONNECT:
err = sys_connect(a0, (struct sockaddr __user *)a1, a[2]);
break;[/code]

asmlinkage long sys_connect(int fd, struct sockaddr __user *uservaddr, int addrlen)
{
struct socket *sock;
char address[MAX_SOCK_ADDR];
int err;

sock = sockfd_lookup(fd, &err);
if (!sock)
goto out;
err = move_addr_to_kernel(uservaddr, addrlen, address);
if (err < 0)
goto out_put;

err = security_socket_connect(sock, (struct sockaddr *)address, addrlen);
if (err) goto out_put;

err = sock->ops->connect(sock, (struct sockaddr *) address, addrlen,
sock->file->f_flags);
out_put:
sockfd_put(sock);
out:
return err;
}

跟其它操作类似,sys_connect 接着调用 inet_connect:
/*
* Connect to a remote host. There is regrettably still a little
* TCP 'magic' in here.
*/
int inet_stream_connect(struct socket *sock, struct sockaddr *uaddr,
int addr_len, int flags)
{
struct sock *sk = sock->sk;
int err;
long timeo;

lock_sock(sk);

if (uaddr->sa_family == AF_UNSPEC) {
err = sk->sk_prot->disconnect(sk, flags);
sock->state = err ? SS_DISCONNECTING : SS_UNCONNECTED;
goto out;
}

提交的协议簇不正确,则断开连接。

switch (sock->state) {
default:
err = -EINVAL;
goto out;
case SS_CONNECTED:
err = -EISCONN;
goto out;
case SS_CONNECTING:
err = -EALREADY;
/* Fall out of switch with err, set for this state */
break;[/code] socket 处于不正确的连接状态,返回相应的错误值。

case SS_UNCONNECTED:
err = -EISCONN;
if (sk->sk_state != TCP_CLOSE)
goto out;
/*调用协议的连接函数*/
err = sk->sk_prot->connect(sk, uaddr, addr_len);
if (err < 0)
goto out;
/*协议方面的工作已经处理完成了,但是自己的一切工作还没有完成,所以切换至正在连接中*/
sock->state = SS_CONNECTING;

/* Just entered SS_CONNECTING state; the only
* difference is that return value in non-blocking
* case is EINPROGRESS, rather than EALREADY.
*/
err = -EINPROGRESS;
break;
}

对于 TCP的实际的连接,是通过调用 tcp_v4_connect()函数来实现的。

二、tcp_v4_connect函数
对于 TCP 协议来说,其连接,实际上就是发送一个 SYN 报文,在服务器的应到到来时,回答它一个 ack 报文,也就是完成三次握手中的第一和第三次。

要发送 SYN 报文,也就是说,需要有完整的来源/目的地址,来源/目的端口,目的地址/端口由用户态提交,但是问题是没有自己的地址和端口,因为并没有调 用过 bind(2),一台主机,对于端口,可以像 sys_bind()那样,从本地未用端口中动态分配一个,那地址呢?因为一台主机可能会存在多个 IP地 址,如果随机动态选择,那么有可能选择一个错误的来源地址,将不能正确地到达目的地址。换句话说,来源地址的选择,是与路由相关的。

调用路由查找的核心函数 ip_route_output_slow(),在没有提供来源地址的情况下,会根据实际情况,调用 inet_select_addr()函数来选择一个合适的。同时,如果路由查找命中,会生成一个相应的路由缓存项,这个缓存项,不但对当前发送 SYN 报 文有意义,对于后续的所有数据包,都可以起到一个加速路由查找的作用。这一任务,是通过 ip_route_connect()函数完成的,它返回相应的路由缓存项(也就是说,来源地址也在其中了):

static inline int ip_route_connect(struct rtable **rp, u32 dst,
u32 src, u32 tos, int oif, u8 protocol,
u16 sport, u16 dport, struct sock *sk)
{ struct flowi fl = { .oif = oif,
.nl_u = { .ip4_u = { .daddr = dst,
.saddr = src,
.tos = tos } },
.proto = protocol,
.uli_u = { .ports =
{ .sport = sport,
.dport = dport } } };

int err;
if (!dst || !src) {
err = __ip_route_output_key(rp, &fl);
if (err)
return err;
fl.fl4_dst = (*rp)->rt_dst;
fl.fl4_src = (*rp)->rt_src;
ip_rt_put(*rp);
*rp = NULL;
}
return ip_route_output_flow(rp, &fl, sk, 0);
}

首先,构建一个搜索 key fl,在搜索要素中,来源地址/端口是不存在的。所以,当通过__ip_route_output_key 进行查找时,第一次是不会命中缓存的。 __ip_route_output_key 将继续调用ip_route_output_slow()函数,在路由表中搜索,并返回一个合适的来源地址, 并且生成一个路由缓存项。 路由查找的更多细节,我会在另一个贴子中来分析。

/* This will initiate an outgoing connection. */
int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
{
struct inet_sock *inet = inet_sk(sk);
struct tcp_sock *tp = tcp_sk(sk);
struct sockaddr_in *usin = (struct sockaddr_in *)uaddr;
struct rtable *rt;
u32 daddr, nexthop;
int tmp;
int err;

if (addr_len < sizeof(struct sockaddr_in))
return -EINVAL;

if (usin->sin_family != AF_INET)

return -EAFNOSUPPORT;

校验地址长度和协议簇。
nexthop = daddr = usin->sin_addr.s_addr;
将下一跳地址和目的地址的临时变量都暂时设为用户提交的地址。

if (inet->opt && inet->opt->srr) {
if (!daddr)
return -EINVAL;
nexthop = inet->opt->faddr;
}
如果使用了来源地址路由,选择一个合适的下一跳地址。

tmp = ip_route_connect(&rt, nexthop, inet->saddr,
RT_CONN_FLAGS(sk), sk->sk_bound_dev_if,
IPPROTO_TCP,
inet->sport, usin->sin_port, sk);
if (tmp < 0)
return tmp;

if (rt->rt_flags & (RTCF_MULTICAST | RTCF_BROADCAST)) {
ip_rt_put(rt);
return -ENETUNREACH;
}
进行路由查找,并校验返回的路由的类型,TCP是不被允许使用多播和广播的。

if (!inet->opt || !inet->opt->srr)
daddr = rt->rt_dst;
更新目的地址临时变量——使用路由查找后返回的值。

if (!inet->saddr)
inet->saddr = rt->rt_src;
inet->rcv_saddr = inet->saddr;
如果还没有设置源地址,和本地发送地址,则使用路由中返回的值。

if (tp->rx_opt.ts_recent_stamp && inet->daddr != daddr) {
/* Reset inherited state */
tp->rx_opt.ts_recent = 0;
tp->rx_opt.ts_recent_stamp = 0;
tp->write_seq = 0;
}

if (sysctl_tcp_tw_recycle &&
!tp->rx_opt.ts_recent_stamp && rt->rt_dst == daddr) {
struct inet_peer *peer = rt_get_peer(rt);
/* VJ's idea. We save last timestamp seen from
* the destination in peer table, when entering state TIME-WAIT
* and initialize rx_opt.ts_recent from it, when trying new connection.
*/

if (peer && peer->tcp_ts_stamp + TCP_PAWS_MSL >= xtime.tv_sec) {
tp->rx_opt.ts_recent_stamp = peer->tcp_ts_stamp;
tp->rx_opt.ts_recent = peer->tcp_ts;
}
}
这个更新初始状态方面的内容,还没有去分析它。

inet->dport = usin->sin_port;
inet->daddr = daddr;
保存目的地址及端口。

tp->ext_header_len = 0;
if (inet->opt)
tp->ext_header_len = inet->opt->optlen;

tp->rx_opt.mss_clamp = 536;
设置最小允许的 mss 值

tcp_set_state(sk, TCP_SYN_SENT);
套接字状态被置为 TCP_SYN_SENT,

err = tcp_v4_hash_connect(sk);
if (err)
goto failure;
动态选择一个本地端口,并加入 hash 表,与bind(2)选择端口类似。

err = ip_route_newports(&rt, inet->sport, inet->dport, sk);
if (err)
goto failure;

/* OK, now commit destination to socket. */
__sk_dst_set(sk, &rt->u.dst);
tcp_v4_setup_caps(sk, &rt->u.dst);
因为本地端口已经改变,使用新端口,重新查找路由,并用新的路由缓存项更新 sk 中保存的路由缓存项。

if (!tp->write_seq)

tp->write_seq = secure_tcp_sequence_number(inet->saddr,
inet->daddr,
inet->sport,
usin->sin_port);
为 TCP报文计算一个 seq值(实际使用的值是 tp->write_seq+1)。

inet->id = tp->write_seq ^ jiffies;

err = tcp_connect(sk);
rt = NULL;
if (err)
goto failure;

return 0;

tp_connect()函数用来根据 sk 中的信息,构建一个完成的 syn 报文,并将它发送出去。在分析 tcp栈的实现时再来分析它。

根据 TCP协议,接下来的问题是,
1、可能收到了服务器的应答,则要回送一个 ack 报文;
2、如果超时还没有应答,则使用超时重发定时器;

Ⅹ linux socket中的connect无法连接

中间加几个调试语句
struct hostent *ho=gethostbyname(url);
if (!ho) fprintf(stderr, "WRONG URL\n");
in.sin_addr.s_addr=((unsigned long *)(ho->h_addr_list[0]))[0];
fprintf(stderr, "ip = %s\n", inet_addr(in.sin_addr.s_addr));
in.sin_family=ho->h_addrtype;
in.sin_port=htons(1234);
connect(sock,(struct sockaddr*)&in,sizeof(in));
你看看解释出来的IP地址对不对,然后用telnet ip 1234试试

阅读全文

与linuxconnect相关的资料

热点内容
数据库管理的优点是 浏览:617
安卓毫秒计时器 浏览:92
hmci模组找不到文件 浏览:348
可复制日语qq网名 浏览:586
电信大数据平台 浏览:348
如何输出一个json数据 浏览:274
未来的编程语言是什么 浏览:694
编程上path是什么意思 浏览:683
u盘外壳3d源文件 浏览:298
中小学如何有效开展编程教育 浏览:6
如何快速拷贝大文件 浏览:406
正柏网络是什么 浏览:834
快手里下载的文件在哪里找 浏览:742
word跨页单元格重复 浏览:616
电视上如何打开压缩文件 浏览:328
电脑管家桌面文件整理 浏览:770
楼宇编程是什么 浏览:802
红警二文件夹 浏览:541
大的mht文件打不开 浏览:467
会计怎么把数据汇总成一本书 浏览:516

友情链接