博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
socket通信介绍
阅读量:3639 次
发布时间:2019-05-21

本文共 5157 字,大约阅读时间需要 17 分钟。

一、socket介绍

Socket即套接字,的英文原义是“孔”或“插座”。作为BSD UNIX的进程通信机制,用于描述IP地址和端口,是一个通信链的句柄,可以用来实现不同虚拟机或不同计算机之间的通信。在Internet上的主机一般运行了多个服务软件,同时提供几种服务。每种服务都打开一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务。Socket正如其英文原义那样,像一个多孔插座。一台主机犹如布满各种插座的房间,每个插座有一个编号,有的插座提供220伏交流电, 有的提供110伏交流电,有的则提供有线电视节目。 客户软件将插头插到不同编号的插座,就可以得到不同的服务。

所以简单的说,socket就是:IP地址+TCP或UDP端口号。

二、socket相关api

1、创建socket

int socket(int domain,int type,int protocol);

domain:即协议域,又称为协议族(family),决定了socket的地址类型。常用的协议族有,AF_INET、AF_INET6、AF_LOCAL(或称                   AF_UNIX,Unix域socket)、AF_ROUTE等,一般我们使用AF_INET。

type:指定socket类型。常用的socket类型有,SOCK_STREAM、SOCK_DGRAM、SOCK_RAW、SOCK_PACKET、                                        SOCK_SEQPACKET等

protocol:指定协议类型,常用的协议有,IPPROTO_TCP、IPPTOTO_UDP、IPPROTO_SCTP、IPPROTO_TIPC等,它们分别对应TCP传输协议、UDP传输协议、STCP传输协议、TIPC传输协议。一般使用默认,设置为0

返回值为套接字描述符

2、绑定

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

sockfd:创建好的socket描述字

addr:指向要绑定给sockfd的协议地址。ipv4和ipv6使用的结构体不同

ipv4:

struct sockaddr_in {    sa_family_t    sin_family; /* address family: AF_INET */    in_port_t      sin_port;   /* port in network byte order */    struct in_addr sin_addr;   /* internet address */};/* Internet address. */struct in_addr {    uint32_t       s_addr;     /* address in network byte order */};

ipv6

struct sockaddr_in6 {     sa_family_t     sin6_family;   /* AF_INET6 */     in_port_t       sin6_port;     /* port number */     uint32_t        sin6_flowinfo; /* IPv6 flow information */     struct in6_addr sin6_addr;     /* IPv6 address */     uint32_t        sin6_scope_id; /* Scope ID (new in 2.4) */ };struct in6_addr {     unsigned char   s6_addr[16];   /* IPv6 address */ };

addrlen:对应的是地址的长度

3、监听

int listen(int sockfd, int backlog);

socked:创建好的socket描述字

backlog:socket可以排队的最大连接个数,一般为5~10

4、请求连接

int accept(int sockfd,struct sockaddr* addr,socklen_t* addrlen);

socked:套接字描述字

addr:用于返回客户端的协议地址

addrlen:协议地址的长度

返回值:成功返回客户端的文件描述符,失败返回-1

5、创建连接

int connect(int sockfd,const struct sockaddr* addr,socklen_t addrlen);

socked:套接字描述字

addr:要结合的地址和端口号,即服务器的socket地址

addrlen:socket地址的长度

6、发送/接收数据

调用网络I/O进行读写操作有一下几组函数。一般使用send/recv

#include 
ssize_t read(int fd, void *buf, size_t count);ssize_t write(int fd, const void *buf, size_t count);
#include 
#include
ssize_t send(int sockfd, const void *buf, size_t len, int flags);ssize_t recv(int sockfd, void *buf, size_t len, int flags);ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);

sockfd:套接字描述字

buf:发送/接收缓冲区

len:缓冲区长度

flags:调用操作方式,具体组合可

返回值为实际写入读出的长度

7,关闭socket

int close(int fd);int shutdown(int sockfd,int how);

 

三、使用socket

服务端即客户端调用顺序如下图:

四、socket通信代码实例

服务端:

#include
#include
#include
#include
#include
#include
#include
#define MAXLINE 4096int main(int argc, char** argv){ int listenfd, connfd; struct sockaddr_in servaddr; char buff[4096]; int n; if( (listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1 ) { printf("create socket error: %s(errno: %d)/n",strerror(errno),errno); exit(0); } memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); //INADDR_ANY表示任何IP servaddr.sin_port = htons(6000); //绑定端口6000 if( bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1) { printf("bind socket error: %s(errno: %d)/n",strerror(errno),errno); exit(0); } if( listen(listenfd, 10) == -1) { printf("listen socket error: %s(errno: %d)/n",strerror(errno),errno); exit(0); } printf("======waiting for client's request======/n"); while(1){ if( (connfd = accept(listenfd, (struct sockaddr*)NULL, NULL)) == -1) { printf("accept socket error: %s(errno: %d)",strerror(errno),errno); continue; } n = recv(connfd, buff, MAXLINE, 0); buff[n] = '/0'; printf("recv msg from client: %s/n", buff); close(connfd); } close(listenfd);}

客户端:

#include
#include
#include
#include
#include
#include
#include
#define MAXLINE 4096int main(int argc, char** argv){ int sockfd, n; char recvline[4096], sendline[4096]; struct sockaddr_in servaddr; if( argc != 2) { printf("usage: ./client
/n"); exit(0); } if( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { printf("create socket error: %s(errno: %d)/n", strerror(errno),errno); exit(0); } memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(6000); if( inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0) { printf("inet_pton error for %s/n",argv[1]); exit(0); } if( connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0) { printf("connect error: %s(errno: %d)/n",strerror(errno),errno); exit(0); } printf("send msg to server: /n"); fgets(sendline, 4096, stdin); if( send(sockfd, sendline, strlen(sendline), 0) < 0) { printf("send msg error: %s(errno: %d)/n", strerror(errno), errno); exit(0); } close(sockfd); exit(0);}

 

 

转载地址:http://vouyn.baihongyu.com/

你可能感兴趣的文章
IntelliJ IDEA中关于Maven构建复杂的聚合工程的管理和打包问题
查看>>
错误记录关于Model 的Not a managed type: class,无法找到Model
查看>>
关于JPA中Specification接口的问题,记录一下
查看>>
IntelliJ IDEA中GIT,已经 commit and push成功,但并未 push 到远程库的问题
查看>>
关于光盘刻录,重洗的一些知识
查看>>
default_Keyword
查看>>
do_Keyword
查看>>
for_Keyword
查看>>
float_Keyword
查看>>
finally_Keyword
查看>>
final_Keyword
查看>>
enum_Keyword
查看>>
extends_Keyword
查看>>
if_Keyword
查看>>
implements_Keyword
查看>>
import_Keyword
查看>>
int_Keyword
查看>>
超详细解读:神经语义解析的结构化表示学习 | 附代码分析
查看>>
在 CentOS 6 里安装 OpenJDK 1.8 和 Tomcat 8.5
查看>>
在 Debian 9 里安装 php5.3 fpm
查看>>