简单的socket通信
服务端代码////Tcp_server.cpp//Cpp////Created by JH on 2020/4/5.//Copyright © 2020 JH. All rights reserved.//#include <stdio.h>#include <iostream>#include <sys/socket.h&g...
服务端代码
//
// Tcp_server.cpp
// Cpp
//
// Created by JH on 2020/4/5.
// Copyright © 2020 JH. All rights reserved.
//
#include <stdio.h>
#include <iostream>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#define PORT 8111
#define MESSAGE_LEN 1024
int main(int argc,char * argv[]){
int ret = -1;
int socket_fd ,accept_fd;
int on =1;
int backlog = 10;
char in_buff[MESSAGE_LEN] ={0};
struct sockaddr_in localaddr,remoteaddr;
socket_fd = socket(AF_INET, SOCK_STREAM, 0);
if (socket_fd == -1) {
exit(-1);
}
ret = setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
if (ret == -1) {
std:: cout << "set option failed" << std::endl;
exit(-1);
}
localaddr.sin_family = AF_INET;
localaddr.sin_port = PORT;
localaddr.sin_addr.s_addr = INADDR_ANY;
bzero(&(localaddr.sin_zero), 8);
ret = bind(socket_fd, (struct sockaddr *)&localaddr, sizeof(struct sockaddr));
if (ret == -1) {
std:: cout << "set bind failed" << std::endl;
exit(-1);
}
ret = listen(socket_fd, backlog);
if (ret == -1) {
std:: cout << "set listen failed" << std::endl;
exit(-1);
}
ssize_t size;
for (; ; ) {
socklen_t addr_len = sizeof(struct sockaddr);
accept_fd = accept(socket_fd, (struct sockaddr *)& remoteaddr, &addr_len);
for (; ; ) {
size = recv(accept_fd, (void *) in_buff, MESSAGE_LEN, 0);
if (size < 0) {
break;
}
std:: cout <<"recv : " <<in_buff << std::endl;
send(accept_fd, (void *)in_buff, MESSAGE_LEN, 0);
}
close(accept_fd);
}
// close(socket_fd);
return 0;
}
客服端代码
//
// Tcp_Client.cpp
// Cpp
//
// Created by JH on 2020/4/7.
// Copyright © 2020 JH. All rights reserved.
//
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <iostream>
#include <unistd.h>
#include <arpa/inet.h>
#define PORT 8111
#define MESSAEG_LEN 1024
int main(int argc,char *argv[]){
int socket_fd;
int ret;
char sendbuf[MESSAEG_LEN] ={0};
char recvbuf[MESSAEG_LEN] ={0};
struct sockaddr_in serveraddr;
ssize_t status;
socket_fd = socket(AF_INET, SOCK_STREAM, 0);
if (socket_fd == -1) {
std::cout<< "failed to create socekt" << std::endl;
exit(-1);
}
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = PORT;
serveraddr.sin_addr.s_addr = inet_addr("127.0.0.1");
socklen_t size =sizeof(struct sockaddr);
ret = connect(socket_fd, (struct sockaddr*)&serveraddr, size);
if (ret < 0) {
std:: cout << "failed to connect server !" <<std::endl;
exit(-1);
}
while (1) {
//清空sendbuf
memset(sendbuf, 0, MESSAEG_LEN);
gets(sendbuf);
status = send(socket_fd, sendbuf, strlen(sendbuf), 0);
if (status < 0) {
std:: cout << "failed to send message !" <<std::endl;
exit(-1);
}
if (strcmp(sendbuf, "quit")==0) {
break;
}
status = recv(socket_fd, recvbuf, MESSAEG_LEN, 0);
recvbuf[status] = '\0';
std:: cout<< "recv:"<<recvbuf <<std::endl;
}
close(socket_fd);
return 0;
}
上面只是一个简单socket通信,实现了客户端发送一段消息给服务端,服务端再返回给客户端。
但是该代码会存在黏包的现象,当客户端连续发送几次消息,服务端第二个收到消息会和第一次收到的消息发生粘连,主要原因是:socket创建时会分配两个缓冲区,输入缓冲区和输出缓冲区。缓冲区的作用主要是为了避免网络不好的时候,消息接收和发送不完整。有了缓冲区,write()/send() 并不立即向网络中传输数据,而是先将数据写入缓冲区中,再由TCP协议将数据从缓冲区发送到目标机器。
当服务端接收到的第一个消息还在缓冲区时,服务端收到第二个消息,此时就会发生黏包现象。
通常做法是在消息发送前添加一个固定字节大小的DataHeader:包含消息id、消息字节大小size等等,客户端和服务端判首先截取消息头,并根据消息头中的size获取消息大小,接收时只有当缓冲区消息头之后的字节大小等于size时,再从缓冲区读取消息。

GitCode 天启AI是一款由 GitCode 团队打造的智能助手,基于先进的LLM(大语言模型)与多智能体 Agent 技术构建,致力于为用户提供高效、智能、多模态的创作与开发支持。它不仅支持自然语言对话,还具备处理文件、生成 PPT、撰写分析报告、开发 Web 应用等多项能力,真正做到“一句话,让 Al帮你完成复杂任务”。
更多推荐
所有评论(0)