原理:TCP网络通信
服务端的流程:
- 1、创建Socket套接字
- 2、给这个socket绑定一个端口
- 3、给这个socket开启监听属性 (这个只能用来接收和连接)
- 4、等待客户端连接
- 5、开始通讯
- 6、关闭连接
客户端的流程:
- 1、创建Socket套接字
- 2、连接服务器
- 3、开始通讯
- 4、关闭连接
服务端代码:
1、创建套接字
//创建Socket套接字
int listen_socket = socket(AF_INET,SOCK_STREAM,0);
if(-1 == listen_socket){
printf("create listen socket failed !!! errcode:");
return -1;
}
AF_INET 是指定套接字的协议簇,常见协议簇包括:
- AF_INET:用于IPv4网络协议。这是最常用的协议族,适用于大多数基于TCP/IP的网络通信。
- AF_INET6:用于IPv6网络协议。
- AF_UNIX或AF_LOCAL:用于本地进程间通信(IPC),通常用于同一台机器上的进程间通信。
SOCK_STREAM指定套接字的类型。常见包括:
- SOCK_STREAM:流式套接字,提供连接的、可靠的、双向的通信。最常用,适用于TCP。
- SOCK_DGRAM:数据报套接字,提供无连接的、不可靠的通信。适用于UDP协议。
- SOCK_RAW:原始套接字,允许直接访问低层协议,通常用于特殊用途。
0为指定具体协议,通常设为0,表示默认标识。对于SOCK_STREAM ,默认协议是TCP;对于 SOCK_STREAM,默认协议是UDP。
返回值,失败返回-1,成功返回非负整数。
2、给这个socket绑定一个端口
struct sockaddr_in local = {0};
local.sin_family = AF_INET;
local.sin_port = htons(8080);
local.sin_addr.s_addr = inet_addr("0.0.0.0");
if(-1==bind(listen_socket, (struct sockaddr*)&local,sizeof(local))){
printf("bind socket failed !!! errcode: ");
return -1;
}
struct sockaddr_in表示是一个IPV4地址结构体,通常用于套接字编程。
sin_family:成员指定地址族
sin_port:成员指定端口号
sin_addr.s_addr:成员指定IP地址。
bind函数将套接字绑定到指定的地址和端口。如果绑定失败,返回值为-1
3、给这个socket开启监听属性
if(-1==listen(listen_socket, 10)){
printf("start listen socket failed !!! ");
return -1;
}
listen函数用于将套接字转换为监听套接字,使其能够接受传入的连接。10为未完成连接队列的最大长度。如果队列已满,新的连接请求将被拒绝。
while (1)
{
/* code */
int client_socket = accept(listen_socket, NULL, NULL);
if(-1 == client_socket){
continue;
}
// 5、开始通讯(B/S)
/*int recv(
SOCKET s; //客户端的socket
char* buf; //接受的数据存在哪里
int len; //接受的长度
int falgs; //0
)
*/
pthread_t thread_id;
int* sockfd = (int*)malloc(sizeof(int));
*sockfd = client_socket;
printf("%d\n",*sockfd);
pthread_create(&thread_id, 0, thread_function, sockfd);
}
accept函数用于接受传入的连接,并为每个连接创建一个新的线程来处理通信。
线程池:
void* thread_function(void* arg) {
int client_socket = *(int*)arg;
printf("%d\n",client_socket);
free(arg);
while (1)
{
/* code */
char buffer[1024]= {0};
int ret = recv(client_socket,buffer, 1024,0);
if(ret<=0) {
break;
}
printf("%d : %s\n",client_socket,buffer);
send(client_socket,buffer,strlen(buffer),0);
}
close(client_socket);
return 0;
}
客户端层次:
1、创建Socket套接字
int client_socket = socket(AF_INET,SOCK_STREAM,0);
if(-1 == client_socket){
printf("create socket failed !!");
return -1;
}
创建客户端套接字
2、连接服务器
struct sockaddr_in target;
target.sin_family = AF_INET;
target.sin_port = htons(8080); //大小端问题
target.sin_addr.s_addr = inet_addr("127.0.0.1");
if(-1 == connect(client_socket,(struct sockaddr*)&target,sizeof(target))){
printf("connect server failed !!");
close(client_socket);
return -1;
}
3、开始通讯
while(1){
char buffer[1024];
printf("please input:");
scanf("%s",buffer);
send(client_socket,buffer,strlen(buffer),0);
char rbuffer[1024];
int ret = recv(client_socket,rbuffer,1024,0);
if(ret<=0){
break;
}
printf("%s\n",rbuffer);
}
4、关闭连接
close(client_socket);
通过线程池可以实现多客户端同时与服务器进行信息发送。