简要概述
创建流程
服务端
- 创建一个套接字 ——socket()
- 绑定IP地址、端口等信息到socket上——bind()
- 监听套接字——listen()
- 等待客户端的连接请求——accept()
- 发送、接收数据——send()和recv(),或者read()和write()
- 关闭网络连接——close()
客户端
- 创建一个套接字——socket()
- 连接服务器——connect()
- 接收、发送数据——send()和recv(),或者read()和write()
- 关闭网络连接——close()
代码分析
实现服务器端向客户端发送信息
以下socket编程用到的函数,可以点击查看具体的socket常用函数解析
服务器端
一、创建一个套接字——socket()
//创建套接字
int serv_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
二、绑定IP地址、端口等信息到socket上——bind()
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr)); //每个字节都用0填充
// 服务器端信息
serv_addr.sin_family = AF_INET; //使用IPv4地址
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); //具体的IP地址
serv_addr.sin_port = htons(1258); //端口
// 将套接字和IP、端口绑定
bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
三、监听套接字——listen()
//进入监听状态,等待用户发起请求
listen(serv_sock, 20);
四、等待客户端的连接请求——accept()
//接收客户端请求
struct sockaddr_in clnt_addr;
socklen_t clnt_addr_size = sizeof(clnt_addr);
int clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_addr, &clnt_addr_size);
五、发送、接收数据——send()和recv(),或者read()和write()
//向客户端发送数据
char str[] = "Hello World!";
write(clnt_sock, str, sizeof(str));
六、关闭网络连接——close()
//关闭套接字
close(clnt_sock);
close(serv_sock);
客户端
一、创建一个套接字——socket()
//创建套接字
int sock = socket(AF_INET, SOCK_STREAM, 0);
二、连接服务器——connect()
先设置要连接的服务器的IP地址和端口等属性,然后连接
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr));
// 服务器端的信息
serv_addr.sin_family = AF_INET; //使用IPv4地址
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); //具体的IP地址
serv_addr.sin_port = htons(1258); //端口
//向服务器(特定的IP和端口)发起请求
connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
三、收发数据——send()和recv(),或者read()和write()
//读取服务器传回的数据
char buffer[40];
read(sock, buffer, sizeof(buffer)-1);
四、关闭网络连接——close()
//关闭套接字
close(sock);
完整代码
服务器端(service.c)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
int main(){
//创建套接字
int serv_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
//将套接字和IP、端口绑定
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr)); //每个字节都用0填充
serv_addr.sin_family = AF_INET; //使用IPv4地址
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); //具体的IP地址
serv_addr.sin_port = htons(1258); //端口
bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
//进入监听状态,等待用户发起请求
listen(serv_sock, 20);
//接收客户端请求
struct sockaddr_in clnt_addr;
socklen_t clnt_addr_size = sizeof(clnt_addr);
int clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_addr, &clnt_addr_size);
//向客户端发送数据
char str[] = "Hello World!";
write(clnt_sock, str, sizeof(str));
//关闭套接字
close(clnt_sock);
close(serv_sock);
return 0;
}
客户端(client.c)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
int main(){
//创建套接字
int sock = socket(AF_INET, SOCK_STREAM, 0);
//向服务器(特定的IP和端口)发起请求
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr)); //每个字节都用0填充
serv_addr.sin_family = AF_INET; //使用IPv4地址
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); //具体的IP地址
serv_addr.sin_port = htons(1258); //端口
connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
//读取服务器传回的数据
char buffer[40];
read(sock, buffer, sizeof(buffer)-1);
printf("Message form server: %s\n", buffer);
//关闭套接字
close(sock);
return 0;
}
运行
(需要开启两个终端)
先分别对两个文件进行编译(分别执行以下两条命令)
gcc service.c -o service
gcc client.c -o client
然后先运行服务器端
./service
再在另一个终端中运行客户端
./client
执行完成
此时服务器端运行结束
客户端也运行结束,并打印出内容
Message form server: Hello World!
服务器端与客户端是全双工连接,即服务器端既可以发送数据也可以接收数据,客户端亦如此