一、socket编程常用函数
1.socket函数
该函数的作用是创建一个套接字,相当于安装一个电话机
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
//成功时返回文件描述符,失败时返回-1
-
domain参数:
- AF_INET, 这是大多数用来产生socket的协议,使用TCP或UDP来传输,用IPv4的地址
- AF_INET6, 与上面类似,不过是来用IPv6的地址
- AF_UNIX, 本地协议,使用在Unix和Linux系统上,一般都是当客户端和服务器在同一台及其上的时候使用
-
type参数:
- SOCK_STREAM 这个协议是按照顺序的、可靠的、数据完整的基于字节流的连接。这是一个使用最多的socket类型,这个socket是使用TCP来进行传输。
- SOCK_DGRAM 这个协议是无连接的、固定长度的传输调用。该协议是不可靠的,使用UDP来进行它的连接。
- SOCK_RAW socket类型提供单一的网络访问,这个socket类型使用ICMP公共协议。(ping、traceroute使用该协议)
- SOCK_RDM 这个类型是很少使用的,在大部分的操作系统上没有实现,它是提供给数据链路层使用,不保证数据包的顺序
-
protocol参数:
- 传0 表示使用默认协议。
2.bind函数
#include <sys/socket.h>
int bind(int sockfd, struct sockaddr *myaddr, socklen_t addrlen);
//成功时返回0,失败时返回-1
- sockfd参数:
- socket文件描述符
- myaddr参数:
- 构造出IP地址加端口号
- addrlen参数:
- sizeof(myaddr)长度
3.listen函数
#include <sys/socket.h>
int listen(int sockfd, int backlog);
//成功时返回0,失败时返回-1
- sockfd参数:
- socket文件描述符
- backlog参数:
- 连接请求等待队列的长度,若为5,则队列长度为5,表示最多使5个连接请求进入队列
4. accept 函数
#include <sys/socket.h>
int accept(int sockfd,struct sockaddr *addr,socklen_t *addrlen);
//成功时返回文件描述符,失败时返回-1
- sockfd参数:
- 服务端套接字的文件描述符
- addr参数:
- 保存发起连接请求的客户端地址信息的变量地址值
- addrlen参数:
- 的第二个参数addr结构体的长度,但是存放有长度的变量地址。
5.connect函数
#include <sys/socket.h>
int connect(int sock, struct sockaddr *servaddr, socklen_t addrlen);
/*
成功时返回0,失败返回-1
*/
- sock参数:
- 客户端套接字文件描述符
- servaddr参数:
- 保存目标服务器端地址信息的变量地址值
- addrlen参数:
- 以字节为单位传递给第二个结构体参数 servaddr 的变量地址长度
6.write函数
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t nbytes);
/*
成功时返回写入的字节数 ,失败时返回 -1
*/
- fd参数:
- 显示数据传输对象的文件描述符
- buf参数:
- 保存要传输数据的缓冲值地址
- nbytes参数:
- 要传输数据的字节数
7.read函数
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t nbytes);
/*
成功时返回接收的字节数(但遇到文件结尾则返回0),失败时返回-1
*/
- fd参数:
- 显示数据接收对象的文件描述符
- buf参数:
- 要保存接收的数据的缓冲地址值。
- nbytes参数:
- 要接收数据的最大字节数
二、echo服务器示例
socket模型创建流程图
1、服务器端
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h> //fork,read,write等系统调用
#include <arpa/inet.h>
#include <sys/socket.h>
#define BUFF_SIZE 1024
void error_handling(char *message);
int main(int argc, char *argv[]) {
if (argc!=2) {
printf("Usage: %s <port>\n", argv[0]);
exit(1);
}
// 1. 创建监听套接字
int serv_sock = socket(PF_INET,SOCK_STREAM,0);// 协议族(IPV4,IPV6),套接字类型(面向连接,面向消息),协议信息(TCP,UDP)
// 2.将socket()返回值和本地的IP端口绑到一起
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(atoi(argv[1])); // 端口号10000,转化为网络字节序,网络传输统一使用大端序
// INADDR_ANY代表本机的所有IP, 假设有三个网卡就有三个IP地址
// 这个宏可以代表任意一个IP地址
addr.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(serv_sock, (struct sokaddr*) &addr, sizeof(addr)) == -1)
error_handling("bind() error");
// 3.设置监听
if (listen(serv_sock, 5) == -1)
error_handling("linsten() error");
struct sockaddr_in clnt_addr;
socklen_t clnt_addr_size = sizeof(clnt_addr);
while(1) {
// 4. 阻塞并等等待客户端连接
int clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_addr, &clnt_addr_size);
if (clnt_sock == -1)
error_handling("accpet() error");
// 5.和客户端通信
// 接收数据
char buf[1024];
int str_len;
memset(buf, 0, sizeof(buf));
while ((str_len = read(clnt_sock, buf, BUFF_SIZE)) != 0)
write(clnt_sock, buf, str_len);
close(clnt_sock);
}
close(serv_sock);
return 0;
}
void error_handling(char *message) {
fputs(message, stderr);
fputs("\n", stderr);
exit(1);
}
二、客户端
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h> //fork,read,write等系统调用
#include <arpa/inet.h>
#include <sys/socket.h>
#define BUFF_SIZE 1024
void error_handling(char *message);
int main(int argc, char *argv[]) {
int sock;
struct sockaddr_in serv_addr;
char message[BUFF_SIZE];
int str_len;
if (argc!=2) {
printf("Usage: %s <IP> <port>\n", argv[0]);
exit(1);
}
// 1.创建客户端套接字
sock = socket(PF_INET, SOCK_STREAM, 0);
if (sock == -1) {
error_handling("socket() error");
}
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); // 将IP地址字符串转化为32位整数类型
serv_addr.sin_port = htons(atoi(argv[1]));
// 2.向服务器端发送连接请求
if (connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) == -1)
error_handling("connect() error");
// 3. 与服务端通信
while (1) {
char buf[1024];
printf("输入要发送的内容,按q退出:");
fgets(buf, BUFF_SIZE, stdin);
if (buf[0] == 'q') break;
str_len=write(sock, buf, sizeof(buf));
int recv_len = 0;
while (recv_len<str_len) {
int cnt_len = read(sock, buf, BUFF_SIZE - 1);
if (cnt_len == -1)
error_handling("read() error");
recv_len += cnt_len;
}
buf[str_len]=0;
printf("Message form server:%s\n", buf);
close(sock);
}
return 0;
}
void error_handling(char *message) {
fputs(message, stderr);
fputs("\n", stderr);
exit(1);
}