1:网络套接字
创建套接字,返回值就是套接字的文件描述符
int socket(int domain,int type,int protocol);//创建一个套接字
//domain(域):确定通信的特性,如AF_INET--IPv4,AF_INET6--IPv6,AF_UNIX--UNIX
//type:确定套接字类型,如SOCKET_STREAM(流式套接字),SOCKET_SEQPACKET(报文传递)
//protocol:确定type下的特定协议,一般用0,表示默认协议,TCP,UDP
将套接字与地址关联
bind(int sockfd,const struct sockaddr* addr,socklen_t len);
//sockfd:由socket返回的套接字的文件描述符
//addr:地址信息
//len:地址长度
设置监听
int listen(int sockfd, int backlog);//socfd套接字文件描述符,backlog,正在请求建立连接的最大数量
等待连接
int accept(int sockfd, void *addr, int *addrlen);
//sockfd:socket()创建的文件描述符
//addr,用来接收客户端传来的地址等基本信息
//addrlen:addr长度
客户端请求建立连接
int connect(int sockfd, struct sockaddr *serv_addr, int addrlen);
//sockfd:客户端的socket()创建的文件描述符
//serv_addr:保存这目的端口和ip等服务器基本信息
//addrlen:serv_addr长度
断开连接(二选一)
close(sockfd);//关闭套接字,进入四次挥手阶段,只是断开当前进程和socket的连接
int shutdown(int sockfd, int how);//端口所有socket连接
2:本地套接字
UNIX域套接字
UNIX域套接字用于同一台计算机上运行的进程之间的通信。他的执行效率更高,仅仅是复制数据,并不执行协议处理,不需要添加和删除网络报头,不需要计算校验和等
只支持流式和数据报两种接口,服务是可靠的,不会丢失报文也不会出错,
创建套接字
这里不用UDP和TCP
int socket(int domain,int type,int protocol);//创建一个套接字
//domain(域):AF_UNIX--UNIX
//type:确定套接字类型,如SOCKET_STREAM(流式套接字),SOCKET_SEQPACKET(报文传递)(其实这个参数并没有用。这里只是占了个位置)
//protocol:确定type下的特定协议
bind 绑定定函数:
unlink(path)//确保之前path文件不存在,bind会创建该文件。。。如果存在这个文件不unlink,bind会失败
int bind(int socket, const struct sockaddr *address, size_t address_len);
sockaddr 此处是
struct sockaddr_un {
sa_family_t sun_family; //AF_UNIX
char sun_path[108]; //表示本地文件路径名,(可以为相对路径也可以为绝对路径) 分为两种一个是普通路径名(linux文件路径)必须以NULL('\0')结尾,
}
客户端请求建立连接
int connect(int sockfd, struct sockaddr *serv_addr, int addrlen);
//sockfd:客户端的socket()创建的文件描述符
//serv_addr:保存服务器sun_path
//addrlen:serv_addr长度
服务器
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "wrap.h"
#define SERV_ADDR "serv.socket"
int main(void)
{
int lfd, cfd, len, size, i;
struct sockaddr_un servaddr, cliaddr;
char buf[4096];
lfd = Socket(AF_UNIX, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sun_family = AF_UNIX;
strcpy(servaddr.sun_path,SERV_ADDR);
len = offsetof(struct sockaddr_un, sun_path) + strlen(servaddr.sun_path); /* servaddr total len */
unlink(SERV_ADDR); /* 确保bind之前serv.sock文件不存在,bind会创建该文件 */
Bind(lfd, (struct sockaddr *)&servaddr, len); /* 参3不能是sizeof(servaddr) */
Listen(lfd, 20);
printf("Accept ...\n");
while (1) {
len = sizeof(cliaddr);
cfd = Accept(lfd, (struct sockaddr *)&cliaddr, (socklen_t *)&len);
len -= offsetof(struct sockaddr_un, sun_path); /* 得到文件名的长度 */
cliaddr.sun_path[len] = '\0'; /* 确保打印时,没有乱码出现 */
printf("client bind filename %s\n", cliaddr.sun_path);
while ((size = read(cfd, buf, sizeof(buf))) > 0) {
for (i = 0; i < size; i++)
buf[i] = toupper(buf[i]);
write(cfd, buf, size);
}
close(cfd);
}
close(lfd);
return 0;
}
客户端
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "wrap.h"
#define SERV_ADDR "serv.socket"
#define CLIE_ADDR "clie.socket"
int main(void)
{
int cfd, len;
struct sockaddr_un servaddr, cliaddr;
char buf[4096];
cfd = Socket(AF_UNIX, SOCK_STREAM, 0);
bzero(&cliaddr, sizeof(cliaddr));
cliaddr.sun_family = AF_UNIX;
strcpy(cliaddr.sun_path,CLIE_ADDR);
len = offsetof(struct sockaddr_un, sun_path) + strlen(cliaddr.sun_path); /* 计算客户端地址结构有效长度 */
unlink(CLIE_ADDR);
Bind(cfd, (struct sockaddr *)&cliaddr, len); /* 客户端也需要bind, 不能依赖自动绑定*/
bzero(&servaddr, sizeof(servaddr)); /* 构造server 地址 */
servaddr.sun_family = AF_UNIX;
strcpy(servaddr.sun_path,SERV_ADDR);
len = offsetof(struct sockaddr_un, sun_path) + strlen(servaddr.sun_path); /* 计算服务器端地址结构有效长度 */
Connect(cfd, (struct sockaddr *)&servaddr, len);
while (fgets(buf, sizeof(buf), stdin) != NULL) {
write(cfd, buf, strlen(buf));
len = read(cfd, buf, sizeof(buf));
write(STDOUT_FILENO, buf, len);
}
close(cfd);
return 0;
}
//注:clie.socket ,serv.socket是socket伪文件,相当于管道,实际不占空间