流程
服务端
- 创建套接字
- 设置套接字属性:允许端口被重新使用
- 设置主机的IP地址和端口号
- 启动服务器监听客户端的请求
- 获取请求简历链接
客户端
- 创建套接字
- 向服务端发送连接请求
- 发送数据
相关API
创建socket
#include <sys/types.h>
#include <sys/socket.h>
/*
参数:
参数1:domain表示通信域
AF_UNIX, AF_LOCAL Local communication unix(7) 本地域
AF_INET IPv4 Internet protocols ip(7) IPV4地址协议族
AF_INET6 IPv6 Internet protocols ipv6(7) IPV6地址协议族
参数2:type表示通信节点的通信方式
SOCK_STREAM 流式套接字类型 TCP 数据通信方式是以字节流形式传输
SOCK_DGRAM 数据报套接字类型 UDP 数据通信方式是以数据包形式传输
SOCK_RAW 原始套接字 可以对底层协议进行修改和访问
参数3:protocol使用的协议号,在SOCK_RAW的时候修改,在默认情况下使用0;
返回值:成功返回通信节点文件描述符,失败返回-1且修改errno的值。
*/
int socket(int domain, int type, int protocol);
设置套接字属性
#include <sys/types.h>
#include <sys/socket.h>
/**
* [setsockopt 设置套接字属性]
* @param sockfd [套接字文件描述符]
* @param level [选项级别,支持SOL_SOCKET、IPPROTO_TCP、IPPROTO_IP和IPPROTO_IPV6]
* @param optname [准备设置的选项]
* @param optval [存放选项待设置的新值]
* @param optlen [optval长度]
* @return [无错返回0,否则返回错误代码]
*/
int setsockopt(int sockfd, int level, int optname,const void *optval, socklen_t optlen);
设置主机IP和端口
#include <sys/types.h>
#include <sys/socket.h>
/**
* [bind 绑定端口和IP]
* @param sockfd [套接字文件描述符]
* @param addr [地址端口等结构体]
* @param addrlen [结构体长度]
* @return [成功返回0,失败返回-1且修改errno的值。]
*/
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
启动服务器监听
#include <sys/types.h>
#include <sys/socket.h>
/**
* [listen 启动监听]
* @param sockfd [套接字文件描述符]
* @param backlog [表示的是挂起连接请求(客户端发出连接请求,服务器还没有响应)队列的大小。
不是已经建立连接成功客户端的个数。]
* @return [成功返回0,失败返回-1且修改errno的值]
*/
int listen(int sockfd, int backlog);
建立连接
#include <sys/types.h>
#include <sys/socket.h>
/**
* [accept 接受建立连接]
* @param sockfd [套接字文件描述符]
* @param addr [是一个结构体指针,指向的空间用来存储返回对端的IP地址和端口信息。]
* @param addrlen [addr结构体大小]
* @return [成功返回新连接客户端的套接字文件描述符,失败返回-1,且修改errno的值]
*/
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
实例
服务器
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
int main()
{
int listenfd;
int connfd;
int ret;
int optval;
struct sockaddr_in srvaddr;
struct sockaddr_in cltaddr;
socklen_t addrlen = sizeof(cltaddr);
char buf[128];
/* 1. 创建TCP流式套接字文件 */
listenfd = socket(AF_INET, SOCK_STREAM, 0);
if (listenfd == -1)
{
perror("socket");
return -1;
}
/* 设置套接字允许IP地址和端口被重新设置 */
optval = 1;/* 允许IP地址和端口被重新设置 */
ret = setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
if (ret == -1)
{
perror("setsockopt");
return -1;
}
/* 2. 设置服务器主机的IP地址和端口号 */
srvaddr.sin_family = AF_INET;
srvaddr.sin_port = htons(8888);
srvaddr.sin_addr.s_addr = htonl(INADDR_ANY);
ret = bind(listenfd, (const struct sockaddr *)&srvaddr, sizeof(srvaddr));
if (ret == -1)
{
perror("bind");
return -1;
}
/* 3. 启动服务器监听客户端的连接请求 */
ret = listen(listenfd, 1024);
if (ret == -1)
{
perror("listen");
return -1;
}
printf("listenfd = %d server init success\n", listenfd);
/* 4. 服务器等待监听客户端的连接请求并建立连接 */
connfd = accept(listenfd, (struct sockaddr *)&cltaddr, &addrlen);
if (connfd == -1)
{
perror("accept");
return -1;
}
printf("connfd = %d client connect success\n", connfd);
/* 5. 服务循环等待客户端的通信数据,并处理数据 */
while(1)
{
/* 接收客户端的数据请求 */
memset(buf, 0, sizeof(buf));
ret = read(connfd, buf, sizeof(buf));
if (ret == -1)
{
perror("read");
return -1;
}
else if (ret == 0)
{
/*说明对端(客户端)退出*/
break;
}
//printf("buf : %s\n", buf);
/* 调用write数据的回写 */
ret = write(connfd, buf, sizeof(buf));
if (ret == -1)
{
perror("write");
return -1;
}
}
}
客户端
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
int main()
{
int ret;
int sockfd;
char buf[128];
struct sockaddr_in srvaddr;
/* 1. 创建TCP流式套接字文件 */
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1)
{
perror("socket");
return -1;
}
/* 2. 向服务器发送连接请求,并建立连接 */
srvaddr.sin_family = AF_INET;
srvaddr.sin_port = htons(8888);/* 服务器的端口号 */
srvaddr.sin_addr.s_addr = inet_addr("192.168.1.130");/* 服务器的IP地址 */
ret = connect(sockfd, (const struct sockaddr *)&srvaddr, sizeof(srvaddr));
if (ret == -1)
{
perror("connect");
return -1;
}
/* 3. 循环向服务器发送数据请求,并接收处理结果*/
while(1)
{
/* 发送数据给服务器 */
fgets(buf, sizeof(buf), stdin);
ret = write(sockfd, buf, sizeof(buf));
if (ret == -1)
{
perror("write");
return -1;
}
/* 接收服务器的处理结果 */
memset(buf, 0, sizeof(buf));
ret = read(sockfd, buf, sizeof(buf));
if (ret == -1)
{
perror("read");
return -1;
}
else if (ret == 0)
{
/* 服务器断开当前客户端的连接 */
break;
}
printf("buf:%s\n", buf);
}
}
网友评论