使用bind来关联地址和套接字
#include <sys/types.h> #include <sys/socket.h> int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); 返回值:成功0,出错-1 sockfd:已经建立的socket描述符 addr:指向sockaddr的结构体指针 addrlen:addr结构的长度
getsockname函数来发现绑定到套接字上的地址
#include <sys/socket.h> int getsockname(int sockfd, struct sockaddr *addr, socklen_t *addrlen); 返回值:成功0,出错-1 sockfd:已经建立的socket描述符 addr:指向sockaddr的结构体指针 addrlen:addr结构的长度
如果套接字已经和对等方连接,可以调用getpeername函数来找到对方的地址
#include <sys/socket.h> int getpeername(int sockfd, struct sockaddr *addr, socklen_t *addrlen); 返回值:成功0,出错-1 sockfd:已经建立的socket描述符 addr:指向sockaddr的结构体指针 addrlen:addr结构的长度
使用connect函数来建立连接
#include <sys/types.h> #include <sys/socket.h> int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); 返回值:成功0,出错-1 sockfd:已经建立的socket描述符
addr:指向sockaddr的结构体指针
addrlen:addr结构的长度
服务器调用listen函数来宣告它愿意接收连接请求
#include <sys/types.h> #include <sys/socket.h> int listen(int sockfd, int backlog); 返回值:成功0,出错-1 sockfd:已经建立的socket描述符 backlog:等待连接队列的最大长度
使用accept函数获取连接请求并建立连接
#include <sys/types.h> #include <sys/socket.h> int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); 返回值:成功文件(套接字)描述符,出错-1 sockfd:已经建立的socket描述符
addr:指向sockaddr的结构体指针
addrlen:addr结构的长度
send和write很像,但是可以指定标志来改变处理传输数据的方式
#include <sys/types.h> #include <sys/socket.h> ssize_t send(int sockfd, const void *buf, size_t len, int flags); 返回值:成功返回发送字节数,出错-1 sockfd:socket描述符 len:缓冲区数据长度 flags:调用执行方式
sendto可以在无连接的套接字上指定一个目标地址
#include <sys/types.h> #include <sys/socket.h> ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen); 返回值:成功发送的字节数,出错-1 sockfd:socket描述符 buf:带发送数据缓冲区 len:缓冲区长度 flags:调用方式标志位,一般为0 dest_addr:指向目的套接字地址 addrlen:所指地址长度
可以调用带有msghdr结构的sendmsg来指定多重缓冲区传输数据,这和writev函数很相似
#include <sys/types.h> #include <sys/socket.h> ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags); 返回值:成功发送的字节数,出错-1 sockfd:socket描述符 msg:信息头结构指针 flags:可选标记参数位,和send或是sendto参数相同
msghdr结构
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
struct msghdr { void *msg_name; /* optional address */ socklen_t msg_namelen; /* size of address */ struct iovec *msg_iov; /* scatter/gather array */ size_t msg_iovlen; /* # elements in msg_iov */ void *msg_control; /* ancillary data, see below */ size_t msg_controllen; /* ancillary data buffer len */ int msg_flags; /* flags (unused) */ };
函数recv和read相似,但是recv可以指定标志来控制如何接收数据
#include <sys/types.h> #include <sys/socket.h> ssize_t recv(int sockfd, void *buf, size_t len, int flags); 返回值:数据字节长度,若无可用数据或对等方已经按序结束返回0,出错-1 sockfd:socket描述符 buf:接收数据缓冲 len:buf的长度 flags:可选标记位
如果发送者已经调用shutdown来结束传输,或者网络协议支持按默认的顺序关闭并且发送端已经关闭,那么当所有的数据接收完毕后,recv会返回0
如果兴趣定位发送者,可以使用recvfrom来得到数据发送者的源地址
#include <sys/types.h> #include <sys/socket.h> ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen); 返回值:返回数据字节长度,若无可用数据或对等方已经按序结束,返回0,出错-1 sockfd:socket描述符 buf:及诶手数据缓冲 len:buf长度 flags:可选标记位 src_addr:如果非空,它将包含数据发送者的套接字端点地址 addrlen:src_addr参数长度
为了将数据送入多个缓冲区,或者想接收辅助数据,可以使用recvmsg
#include <sys/types.h> #include <sys/socket.h> ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags); 返回值:返回数据的自及诶长度,若无可用数据或对等方已经按序结束,返回0,出错-1 sockfd:socket描述符 msg:信息头结构指针 flags:可选标志位
可以使用setsockopt函数来设置套接字选项
#include <sys/types.h> #include <sys/socket.h> int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen); 返回值:成功0,失败-1 sockfd:socket描述符 level:标识了选项应用的协议 optname:需要设置的选项 optval:指向存放选项值的缓冲区指针 optlen:optval的长度
可以使用getsockopt函数来查看选项的当前值
#include <sys/types.h> #include <sys/socket.h> int getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen); 返回值:成功0,失败-1 sockfd:socket描述符 level:标识了选项应用的协议 optname:需要设置的选项 optval:指向存放选项值的缓冲区指针 optlen:指向optval缓冲区的长度
TCP例程:
服务器端:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <sys/types.h> 4 #include <sys/socket.h> 5 #include <netinet/in.h> 6 #include <arpa/inet.h> 7 #include <string.h> 8 9 #define MAXLINE 80 10 #define SERV_PORT 8000 11 12 int main(void) 13 { 14 char buf[MAXLINE]; 15 int listenfd = 0; 16 17 listenfd = socket(AF_INET, SOCK_STREAM, 0); 18 19 struct sockaddr_in servaddr = {0}; 20 servaddr.sin_family = AF_INET; 21 servaddr.sin_port = htons(SERV_PORT); 22 servaddr.sin_addr.s_addr = htonl(INADDR_ANY); 23 24 bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)); 25 listen(listenfd, 20); 26 27 printf("Accepting connections ... "); 28 while(1) 29 { 30 struct sockaddr_in cliaddr = {0}; 31 socklen_t cliaddr_len = sizeof(cliaddr); 32 int connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len); 33 34 char str[INET_ADDRSTRLEN]; 35 printf("connect from %s at PORT %d ", 36 inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)), 37 ntohs(cliaddr.sin_port)); 38 while(1) 39 { 40 int count = read(connfd, buf, MAXLINE); 41 if(count == 0) 42 break; 43 44 write(connfd, buf, count); 45 } 46 close(connfd); 47 printf("closed from %s at PORT %d ", 48 inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)), 49 ntohs(cliaddr.sin_port)); 50 } 51 }
客户端:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <stdio.h> 2 #include <arpa/inet.h> 3 #include <stdlib.h> 4 #include <unistd.h> 5 #include <sys/socket.h> 6 #include <netinet/in.h> 7 8 #define MAXLINE 80 9 #define SERV_PORT 8000 10 #define MESSAGE "hello world" 11 12 int main(int argc, char *argv[]) 13 { 14 char buf[MAXLINE]; 15 16 int sockfd = socket(AF_INET, SOCK_STREAM, 0); 17 18 struct sockaddr_in servaddr = {0}; 19 servaddr.sin_family = AF_INET; 20 inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr); 21 servaddr.sin_port = htons(SERV_PORT); 22 23 if(connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) != 0) 24 { 25 printf("connected failed"); 26 return 1; 27 } 28 29 write(sockfd, MESSAGE, sizeof(MESSAGE)); 30 int count = read(sockfd, buf, MAXLINE); 31 32 printf("Response from server: %s ", buf); 33 34 close(sockfd); 35 return 0; 36 }