包含头文件:
#include <netinet/in.h> //常变量
#include <sys/socket.h> //函数
主要函数:
1、socket
创建套接字
int socket(int domian, int type, int protocol);
domain
指定应用程序使用的通信协议的协议族,对于TCP/IP该参数应该为AF_INET或AF_INET6,分别表示IPv4和IPv6地址协议族
type
指定创建套接字的类型,流套接字SOCKET_STREAM,数据报套接字SOCKET_DGRAM,原始套接字SOCKET_RAW
protocol
指定应用程序所使用的通信协议。此参数可以指定单个协议系列中的不同传输协议。在Internet通讯域中,此参数一般取值为0,系统会根据套接字的类型决定应使用的传输层协议。
成功就返回新创建的套接字的描述符,失败就返回INVALID_SOCKET。(Linux下失败返回-1)
每个进程的进程空间里都有一个套接字描述表,该表中存放着套接字描述符和套接字数据结构的对应关系。其一个字段存放套接字描述符,另一个字段存放套接字数据结构的地址,因此根据套接字描述符就可以找到其对应的套接字数据结构。
每个进程在自己的进程空间里有一个套接字描述符表,但是套接字数据结构都是在操作系统的内核缓冲里。
2、bind
绑定套接字,将套接字绑定到指定地址。
int bind(int sockfd, struct sockaddr * addr, socklen_t addrlen);
sockfd
由socket函数返回的套接字。
addr
是一个地址结构,并且是一个已经进过填写的有效的地址结构。
addrlen
地址结构的大小。内核不关心地址结构,当它复制或传递地址给驱动的时候,它依据这个值来确定需要复制多少数据。
bind函数并不是总是需要调用的,只有用户进程想与一个具体的地址或端口相关联的时候才需要调用这个函数。如果用户进程没有这个需要,那么程序可以依赖内核的自动的选址机制来完成自动地址选址,而不需要调用bind函数,同时也避免不必要的复杂度。
一般情况下,对于服务器进程问题需要调用bind函数,对于客户端进程则不需要调用bind函数。
struct sockaddr{
u_short sa_family; //协议族,通常是AF_INET代表TCP/IP协议族。
char sa_data[14];
}
struct sockaddr_in{
short sin_family;
unsigned short sin_port; //网络数据格式的端口号,可用htons()函数转换。
struct in_addr sin_addr; //IP地址
unsigned char sin_zero[8];//没有实际意义,只是为了跟struct sockaddr在内存中对齐
}
typedef struct in_addr{
unsigned long s_addr;
}
3、listen
使主动连接套接字编程被动连接套接字,使进程可以接收其他进程的请求。
int listen(int sockfd, int backlog);
backlog
新建连接请求时,最大的未处理的积压请求数。
4.accept
用来接收客户端连接请求。会阻塞线程,直到有一个客户连接建立后返回,它返回的是一个新的可用的套接字,这个套接字是连接套接字。
int accept(int sockfd, struct sockaddr *addr, socklen_t *len);
addr
接受一个返回值,这个返回值指定客户端的地址。
len
addr参数的长度。
5.connect
主动连接。
int connect(int sockfd, const struct sockaddr * server_addr, socklen_t addrlen);
sockfd
指定数据发送套接字,解决从哪里发送的问题。内核需要维护大量IO通道,所以用户必须通过这个参数告诉内核从哪个IO通道发送数据。
server_addr
指定数据发送的目的地,也就是服务器的地址。
addrlen
指定server_addr结构体的长度。
成功返回0,失败返回-1.
6.close
关闭套接字。
7.send/recv
8.sendto/recvfrom
9.sendmsg/recvmsg
在已经建立了连接的套接字之间发送和接收数据。
ssize_t send(int sockfd, const void *buf, ssize_t len, int flags);
ssize_t sendto(int sockfd, const void *buf, ssize_t len, int flags, const struct sockaddr *to, socklen_t tolen);
ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
ssize_t recv(int sockfd, void *buf, int len, int flags);
ssize_t recvfrom(int sockfd, void *buf, ssize_t len, int flags, struct sockaddr *from, socklen_t *fromlen);
ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
struct msghdr{
void * msg_name;
socklen_t msg_namelen;
struct iovec * msg_iov;
int msg_iovlen;
void * msg_control;
socklen_t msg_controllen;
int msg_flags;
};
flags
用于改变函数行为
flags=0 与write无异
flags=MSG_DONTROUTE 告诉内核,目标主机在本地网络,不用查路由表
flags=MSG_DONTWAIT 将单个I/O操作设置为非阻塞模式
flags=MSG_OOB 指明发送的是外带消息
...
10.getsockopt/setsockopt
11.getpeername/getsockname
12.socketpair
13.accept4
14.shutdown
其他重要函数
1.htons
将数字端口转换成网络数据格式的端口。
struct sockaddr_in sin;
sin.sin_port = htons(10001);
2.gethostbyname
传入域名或主机名,返回一个hostent结构。
struct hostent *gethostbyname(cosnt char *name);
struct hostent *hptr;
hptr = gethostbyname("www.baidu.com");
struct hostent{
char *h_name; //主机的规范名。www.google.com的规范名其实是www.l.google.com
char **h_aliases; //主机的别名。有的主机可能有好几个别名,易于用户记忆。
int h_addrtype; //主机ip地址类型,ipv4-AF_INET,ipv6-AF_INET6。
int h_length; //主机ip地址的长度。
char **h_addr_list; //主机的ip地址,以网络字节序存储的。需要调用inet_ntop()来打印。
};
const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt);
in_addr_t inet_addr(const char *cp);//
/* sys/socket.h
Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2005, 2006,
2009, 2010 Red Hat, Inc.
This file is part of Cygwin.
This software is a copyrighted work licensed under the terms of the
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */
#ifndef _SYS_SOCKET_H
#define _SYS_SOCKET_H
#include <features.h>
#include <cygwin/socket.h>
#include <sys/time.h>
#ifdef __cplusplus
extern "C"
{
#endif
/* SUS symbolic values for the second parm to shutdown(2) */
#define SHUT_RD 0 /* == Win32 SD_RECEIVE */
#define SHUT_WR 1 /* == Win32 SD_SEND */
#define SHUT_RDWR 2 /* == Win32 SD_BOTH */
#ifndef __INSIDE_CYGWIN_NET__
int accept (int, struct sockaddr *__peer, socklen_t *);
int accept4 (int, struct sockaddr *__peer, socklen_t *, int flags);
int bind (int, const struct sockaddr *__my_addr, socklen_t __addrlen);
int connect (int, const struct sockaddr *, socklen_t);
int getpeername (int, struct sockaddr *__peer, socklen_t *);
int getsockname (int, struct sockaddr *__addr, socklen_t *);
int listen (int, int __n);
ssize_t recv (int, void *__buff, size_t __len, int __flags);
ssize_t recvfrom (int, void *__buff, size_t __len, int __flags,
struct sockaddr *__from, socklen_t *__fromlen);
ssize_t recvmsg(int s, struct msghdr *msg, int flags);
ssize_t send (int, const void *__buff, size_t __len, int __flags);
ssize_t sendmsg(int s, const struct msghdr *msg, int flags);
ssize_t sendto (int, const void *, size_t __len, int __flags,
const struct sockaddr *__to, socklen_t __tolen);
int setsockopt (int __s, int __level, int __optname, const void *optval,
socklen_t __optlen);
int getsockopt (int __s, int __level, int __optname, void *__optval,
socklen_t *__optlen);
int shutdown (int, int);
int socket (int __family, int __type, int __protocol);
int socketpair (int __domain, int __type, int __protocol, int *__socket_vec);
struct servent *getservbyname (const char *__name, const char *__proto);
#endif
#ifdef __cplusplus
};
#endif
#endif /* _SYS_SOCKET_H */