现在的位置: 首页 > 综合 > 正文

netcat源代码分析,udp模式(1)服务端如何得到客户端的ip地址和端口号?

2013年03月21日 ⁄ 综合 ⁄ 共 2520字 ⁄ 字号 评论关闭

/* UDP is a speeeeecial case -- we have to do I/O *and* get the calling
   party's particulars all at once, listen() and accept() don't apply.
   At least in the BSD universe, however, recvfrom/PEEK is enough to tell
   us something came in, and we can set things up so straight read/write
   actually does work after all.  Yow.  YMMV on strange platforms!  */
  if (o_udpmode) {
    x = sizeof (SA);        /* retval for recvfrom */
    arm (2, o_wait);        /* might as well timeout this, too */
    if (setjmp (jbuf) == 0) {    /* do timeout for initial connect */

fprintf(stderr,"  0remend->sin_addr.sin_port = %u \n",ntohs(remend->sin_port));

fprintf(stderr,"  0remend->sin_addr.sin_addr = %s \n",inet_ntoa(remend->sin_addr));

      rr = recvfrom        /* and here we block... */
    (nnetfd, bigbuf_net, BIGSIZ, MSG_PEEK, (SA *) remend, &x);
fprintf(stderr,"  1remend->sin_addr.sin_port = %u \n",ntohs(remend->sin_port));
fprintf(stderr,"  1remend->sin_addr.sin_addr = %s \n",inet_ntoa(remend->sin_addr));
Debug (("dolisten/recvfrom ding, rr = %d, netbuf %s ", rr, bigbuf_net))


    } else
      goto dol_tmo;        /* timeout */
    arm (0, 0);
/* I'm not completely clear on how this works -- BSD seems to make UDP
   just magically work in a connect()ed context, but we'll undoubtedly run
   into systems this deal doesn't work on.  For now, we apparently have to
   issue a connect() on our just-tickled socket so we can write() back.
   Again, why the fuck doesn't it just get filled in and taken care of?!
   This hack is anything but optimal.  Basically, if you want your listener
   to also be able to send data back, you need this connect() line, which
   also has the side effect that now anything from a different source or even a
   different port on the other end won't show up and will cause ICMP errors.
   I guess that's what they meant by "connect".
   Let's try to remember what the "U" is *really* for, eh?
*/
    rr = connect (nnetfd, (SA *)remend, sizeof (SA));
    goto whoisit;
  } /* o_udpmode */

函数原型:ssize_t recvfrom(int sockfd,void *buf,int len,unsigned int flags, struct sockaddr *from,socket_t *fromlen); ssize_t 相当于 int,socket_t 相当于int ,这里用这个名字为的是提高代码的自说明性。
参数:
sockfd:标识一个已连接套接口的描述字。 
buf:接收数据缓冲区。 
len:缓冲区长度。 
flags:调用操作方式。

MSG_PEEK:指示数据接收后,在接收队列中保留原数据,不将其删除,随后的读操作还可以接收相同的数据。

from:(可选)指针,指向装有源地址的缓冲区。 
fromlen:(可选)指针,指向from缓冲区长度值。
返回值:
如果正确接收返回接收到的字节数,失败返回0.

G:\nc\nc115-debug>nc -ulp 66
in res_init
after recycle
after go: x now , optarg 0 optind 3
curport = (null)
in dolisten lp = 66
in doconnect
in doconnect ,listen socket nnetfd = 1864.
in dolisten nnetfd = 1864
in arm num = 2 stdhnd = 7
handle is 7
  0remend->sin_addr.sin_port = 0
  0remend->sin_addr.sin_addr = 0.0.0.0
  1remend->sin_addr.sin_port = 2095
  1remend->sin_addr.sin_addr = 127.0.0.1
dolisten/recvfrom ding, rr = 2, netbuf d

in arm num = 0 stdhnd = 7
handle is 7
remend->sin_port = 1837
bigbuf_net = 127.0.0.1
in dolisten , socket nnetfd = 1864.
got 2 from the net, errno 0

抱歉!评论已关闭.