Linux网络编程基础2:socket,bind,listen,accept,close函数

img

1.创建socket

#include<sys/types.h>
#include<sys/socket.h>
int socket(int domain,int type,int protocol);
  • domain:表示协议族,对于UNIX要填写PF_UNIX,对于TCP/IP要填写PF_INET。
  • type:表示服务类型,对于TCP要填写SOCK_STREAM,对于UDP要填写SOCK_DGRAM。
  • protocol:前2个参数更具体的补充,几乎所有情况下,我们都填写0,因为乌龟的屁股。

socket在UNIX/LINUX是一个文件,可读,可写,可控制,可关闭的文件描述符。自内核2.6.17起,type参数可以与上SOCK_NONBLOCK和SOCK_CLOEXEC,前者表示非阻塞的,后者表示fork出来关闭掉子进程的socket,之前只能用fctl函数啦。socket函数成功时候返回socket文件描述符,失败就返回-1并且设置errno。

2.绑定socket

#include<sys/types.h>
#include<sys/socket.h>
int bind(int sockfd,const struct sockaddr * my_addr,socklen_t addrlen);
  • sockfd 和 my_addr 进行捆绑在一起。
  • addrlen:my_addr的长度。

前面的socket函数成功返回可以获得一个socket描述符,但是需要指定具体的socket地址,也可以称为给socket命名。如果不命名,那客户端就不知道如何连接它,但是客户端采用匿名方式就好了不需要绑定,这点需要注意。

my_addr的类型为struct sockaddr,这和前文强调过,地址族结构体作为参数的只有struct sockaddr。

bind函数成功时返回0,失败返回-1并设置errno。errno有两种常见的:

  • EACCES:普通用户无法访问root的知名端口(0~1023)
  • EADDRINUSE:绑定的地址正在使用中。
    所以绑定之前,应该通过netstate,ss等命令先对端口进行查看一下,这样更加严谨一些,之前自己也从来没有考虑过这个问题,好的,现在又向大佬迈进重要的一步。
netstat -nt | grep 8888

3.监听socket

#include<sys/socket.h>
int listen(int sockfd,int backlog);
  • sockfd:指定被监听的socket。
  • backlog:提示内核监听队列的最大长度,长度如果超过该值,服务器不受理新的客户端连接。客户端收到ECONNREFUSED错误信息。实际上,监听队列中完整的连接比上限略大。内核版本2.2之前表示处于半连接和全连接的上限,但是之后只表示完全连接的上限。内核2.2之后只表示完全连接的数量,半连接的数量在下图中显示
    在这里插入图片描述
    listen函数成功返回0,失败返回-1并设置errno。

4.接受连接

#include<sys/types.h>
#include<sys/socket.h>
int accept(int sockfd,struct sockaddr * addr,socklen_t * addrlen);
  • sockfd:监听socket。
  • addr:被接受连接的远端socket地址。这个参数是传出参数,获取对端连接的地址。
  • addrlen :addr地址的长度。

accept函数成功时返回一个监听socket,标识了被接受的这个连接,服务器通过读写这个socket与对端通信。失败时返回-1并设置errno。

accept函数用于从完成队列中取出连接,并生成监听socket进行通信。值得注意的点是,在监听和接受连接的中间环节,不管客户端是切断网线还是优雅退出,服务器都感知不到这个网络状态的变化,依然会继续与对端通信,协议栈会把连接通过超时的方式释放掉。

5.发起连接

#include<sys/types.h>
#include<sys/socket.h>
int connect(int sockfd,const struct sockaddr * serv_addr,socklen addrlen);
  • sockfd:客户端调用socket函数返回的一个socket。
  • :服务器监听的socket地址。
  • addrlen:serv_addr地址的长度。

connect成功时返回0,失败返回-1并设置errno。两个常见的错误:

  • ECONNREFUSED:目标端口不存在,连接被拒绝。
  • ETIMEDOUT:连接超时,客户端可能访问的是很远的服务器,或者服务器繁忙,请求多次都没有响应。
if ( connect( sockfd, ( struct sockaddr* )&server_address, sizeof( server_address ) ) < 0 ) 
        printf( "connection failed\n" );
    else
        printf( "send oob data out\n" );

6.关闭连接

#include<unistd.h>
int close(int sockfd);
  • sockfd:待关闭的socket。

close函数并非立即关闭,只是将引用计数减1,直到为0才关闭。

#include<sys/socket.h>
int shutdown(int sockfd,int howto);
  • sockfd:待关闭的socket。
  • howto:如何关闭socket。

howto可选如下的值:

  • SHUT_RD:关闭读的一半,接受缓冲区的数据都被丢弃。
  • SHUT_WR:关闭写的一半,关闭之前发送数据,而
  • SHUT_RDWR:读写都关闭。
    shutdown成功时返回0,失败返回-1并设置errno。shutdown比close更灵活一些。
#include<sys/socket.h>

不难发现,系统API都要包含这个头文件,下面展示一下这个头文件里包含了哪些函数。

/* Declarations of socket constants, types, and functions.
   Copyright (C) 1991-2020 Free Software Foundation, Inc.
   This file is part of the GNU C Library.

   The GNU C Library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2.1 of the License, or (at your option) any later version.

   The GNU C Library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with the GNU C Library; if not, see
   <https://www.gnu.org/licenses/>.  */

#ifndef	_SYS_SOCKET_H
#define	_SYS_SOCKET_H	1

#include <features.h>

__BEGIN_DECLS

#include <bits/types/struct_iovec.h>
#define	__need_size_t
#include <stddef.h>

/* This operating system-specific header file defines the SOCK_*, PF_*,
   AF_*, MSG_*, SOL_*, and SO_* constants, and the `struct sockaddr',
   `struct msghdr', and `struct linger' types.  */
#include <bits/socket.h>

#ifdef __USE_MISC
# include <bits/types/struct_osockaddr.h>
#endif

/* The following constants should be used for the second parameter of
   `shutdown'.  */
enum
{
  SHUT_RD = 0,		/* No more receptions.  */
#define SHUT_RD		SHUT_RD
  SHUT_WR,		/* No more transmissions.  */
#define SHUT_WR		SHUT_WR
  SHUT_RDWR		/* No more receptions or transmissions.  */
#define SHUT_RDWR	SHUT_RDWR
};

/* This is the type we use for generic socket address arguments.

   With GCC 2.7 and later, the funky union causes redeclarations or
   uses with any of the listed types to be allowed without complaint.
   G++ 2.7 does not support transparent unions so there we want the
   old-style declaration, too.  */
#if defined __cplusplus || !__GNUC_PREREQ (2, 7) || !defined __USE_GNU
# define __SOCKADDR_ARG		struct sockaddr *__restrict
# define __CONST_SOCKADDR_ARG	const struct sockaddr *
#else
/* Add more `struct sockaddr_AF' types here as necessary.
   These are all the ones I found on NetBSD and Linux.  */
# define __SOCKADDR_ALLTYPES \
  __SOCKADDR_ONETYPE (sockaddr) \
  __SOCKADDR_ONETYPE (sockaddr_at) \
  __SOCKADDR_ONETYPE (sockaddr_ax25) \
  __SOCKADDR_ONETYPE (sockaddr_dl) \
  __SOCKADDR_ONETYPE (sockaddr_eon) \
  __SOCKADDR_ONETYPE (sockaddr_in) \
  __SOCKADDR_ONETYPE (sockaddr_in6) \
  __SOCKADDR_ONETYPE (sockaddr_inarp) \
  __SOCKADDR_ONETYPE (sockaddr_ipx) \
  __SOCKADDR_ONETYPE (sockaddr_iso) \
  __SOCKADDR_ONETYPE (sockaddr_ns) \
  __SOCKADDR_ONETYPE (sockaddr_un) \
  __SOCKADDR_ONETYPE (sockaddr_x25)

# define __SOCKADDR_ONETYPE(type) struct type *__restrict __##type##__;
typedef union { __SOCKADDR_ALLTYPES
	      } __SOCKADDR_ARG __attribute__ ((__transparent_union__));
# undef __SOCKADDR_ONETYPE
# define __SOCKADDR_ONETYPE(type) const struct type *__restrict __##type##__;
typedef union { __SOCKADDR_ALLTYPES
	      } __CONST_SOCKADDR_ARG __attribute__ ((__transparent_union__));
# undef __SOCKADDR_ONETYPE
#endif

#ifdef __USE_GNU
/* For `recvmmsg' and `sendmmsg'.  */
struct mmsghdr
  {
    struct msghdr msg_hdr;	/* Actual message header.  */
    unsigned int msg_len;	/* Number of received or sent bytes for the
				   entry.  */
  };
#endif


/* Create a new socket of type TYPE in domain DOMAIN, using
   protocol PROTOCOL.  If PROTOCOL is zero, one is chosen automatically.
   Returns a file descriptor for the new socket, or -1 for errors.  */
extern int socket (int __domain, int __type, int __protocol) __THROW;

/* Create two new sockets, of type TYPE in domain DOMAIN and using
   protocol PROTOCOL, which are connected to each other, and put file
   descriptors for them in FDS[0] and FDS[1].  If PROTOCOL is zero,
   one will be chosen automatically.  Returns 0 on success, -1 for errors.  */
extern int socketpair (int __domain, int __type, int __protocol,
		       int __fds[2]) __THROW;

/* Give the socket FD the local address ADDR (which is LEN bytes long).  */
extern int bind (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len)
     __THROW;

/* Put the local address of FD into *ADDR and its length in *LEN.  */
extern int getsockname (int __fd, __SOCKADDR_ARG __addr,
			socklen_t *__restrict __len) __THROW;

/* Open a connection on socket FD to peer at ADDR (which LEN bytes long).
   For connectionless socket types, just set the default address to send to
   and the only address from which to accept transmissions.
   Return 0 on success, -1 for errors.

   This function is a cancellation point and therefore not marked with
   __THROW.  */
extern int connect (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len);

/* Put the address of the peer connected to socket FD into *ADDR
   (which is *LEN bytes long), and its actual length into *LEN.  */
extern int getpeername (int __fd, __SOCKADDR_ARG __addr,
			socklen_t *__restrict __len) __THROW;


/* Send N bytes of BUF to socket FD.  Returns the number sent or -1.

   This function is a cancellation point and therefore not marked with
   __THROW.  */
extern ssize_t send (int __fd, const void *__buf, size_t __n, int __flags);

/* Read N bytes into BUF from socket FD.
   Returns the number read or -1 for errors.

   This function is a cancellation point and therefore not marked with
   __THROW.  */
extern ssize_t recv (int __fd, void *__buf, size_t __n, int __flags);

/* Send N bytes of BUF on socket FD to peer at address ADDR (which is
   ADDR_LEN bytes long).  Returns the number sent, or -1 for errors.

   This function is a cancellation point and therefore not marked with
   __THROW.  */
extern ssize_t sendto (int __fd, const void *__buf, size_t __n,
		       int __flags, __CONST_SOCKADDR_ARG __addr,
		       socklen_t __addr_len);

/* Read N bytes into BUF through socket FD.
   If ADDR is not NULL, fill in *ADDR_LEN bytes of it with tha address of
   the sender, and store the actual size of the address in *ADDR_LEN.
   Returns the number of bytes read or -1 for errors.

   This function is a cancellation point and therefore not marked with
   __THROW.  */
extern ssize_t recvfrom (int __fd, void *__restrict __buf, size_t __n,
			 int __flags, __SOCKADDR_ARG __addr,
			 socklen_t *__restrict __addr_len);


/* Send a message described MESSAGE on socket FD.
   Returns the number of bytes sent, or -1 for errors.

   This function is a cancellation point and therefore not marked with
   __THROW.  */
extern ssize_t sendmsg (int __fd, const struct msghdr *__message,
			int __flags);

#ifdef __USE_GNU
/* Send a VLEN messages as described by VMESSAGES to socket FD.
   Returns the number of datagrams successfully written or -1 for errors.

   This function is a cancellation point and therefore not marked with
   __THROW.  */
extern int sendmmsg (int __fd, struct mmsghdr *__vmessages,
		     unsigned int __vlen, int __flags);
#endif

/* Receive a message as described by MESSAGE from socket FD.
   Returns the number of bytes read or -1 for errors.

   This function is a cancellation point and therefore not marked with
   __THROW.  */
extern ssize_t recvmsg (int __fd, struct msghdr *__message, int __flags);

#ifdef __USE_GNU
/* Receive up to VLEN messages as described by VMESSAGES from socket FD.
   Returns the number of messages received or -1 for errors.

   This function is a cancellation point and therefore not marked with
   __THROW.  */
extern int recvmmsg (int __fd, struct mmsghdr *__vmessages,
		     unsigned int __vlen, int __flags,
		     struct timespec *__tmo);
#endif

/* Put the current value for socket FD's option OPTNAME at protocol level LEVEL
   into OPTVAL (which is *OPTLEN bytes long), and set *OPTLEN to the value's
   actual length.  Returns 0 on success, -1 for errors.  */
extern int getsockopt (int __fd, int __level, int __optname,
		       void *__restrict __optval,
		       socklen_t *__restrict __optlen) __THROW;

/* Set socket FD's option OPTNAME at protocol level LEVEL
   to *OPTVAL (which is OPTLEN bytes long).
   Returns 0 on success, -1 for errors.  */
extern int setsockopt (int __fd, int __level, int __optname,
		       const void *__optval, socklen_t __optlen) __THROW;


/* Prepare to accept connections on socket FD.
   N connection requests will be queued before further requests are refused.
   Returns 0 on success, -1 for errors.  */
extern int listen (int __fd, int __n) __THROW;

/* Await a connection on socket FD.
   When a connection arrives, open a new socket to communicate with it,
   set *ADDR (which is *ADDR_LEN bytes long) to the address of the connecting
   peer and *ADDR_LEN to the address's actual length, and return the
   new socket's descriptor, or -1 for errors.

   This function is a cancellation point and therefore not marked with
   __THROW.  */
extern int accept (int __fd, __SOCKADDR_ARG __addr,
		   socklen_t *__restrict __addr_len);

#ifdef __USE_GNU
/* Similar to 'accept' but takes an additional parameter to specify flags.

   This function is a cancellation point and therefore not marked with
   __THROW.  */
extern int accept4 (int __fd, __SOCKADDR_ARG __addr,
		    socklen_t *__restrict __addr_len, int __flags);
#endif

/* Shut down all or part of the connection open on socket FD.
   HOW determines what to shut down:
     SHUT_RD   = No more receptions;
     SHUT_WR   = No more transmissions;
     SHUT_RDWR = No more receptions or transmissions.
   Returns 0 on success, -1 for errors.  */
extern int shutdown (int __fd, int __how) __THROW;


#ifdef __USE_XOPEN2K
/* Determine whether socket is at a out-of-band mark.  */
extern int sockatmark (int __fd) __THROW;
#endif

#ifdef __USE_MISC
/* FDTYPE is S_IFSOCK or another S_IF* macro defined in <sys/stat.h>;
   returns 1 if FD is open on an object of the indicated type, 0 if not,
   or -1 for errors (setting errno).  */
extern int isfdtype (int __fd, int __fdtype) __THROW;
#endif

/* Define some macros helping to catch buffer overflows.  */
#if __USE_FORTIFY_LEVEL > 0 && defined __fortify_function
# include <bits/socket2.h>
#endif

__END_DECLS

#endif /* sys/socket.h */
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

屯门山鸡叫我小鸡

加油

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值