代码
相互收发
server代码
/**********
1、在服务器端接受消息时知道对方的IP和端口
提示:
bind出现:Address already in use 方法:netstat -nap查看 用kill -9 pid杀死
2、利用TCP实现文件传输
**********/
#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <strings.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/stat.h>
#include <fcntl.h>
#include<stdlib.h>//
#include<netinet/in.h>//
int main(void)
{
//建立套接字
int server_fd=socket(AF_INET,SOCK_STREAM,0);
if(server_fd==-1)
{
perror("socket:");
return -1;
}
//设置套接字可以使用本机ip端口,否则ip只能用127.0.0.0
int on_soc = 1;
if(setsockopt(server_fd,SOL_SOCKET,SO_REUSEADDR,&on_soc,sizeof(on_soc))<0)
{
perror("fial to setsockopt");
exit(1);
}
//绑定本机的IP和端口
struct sockaddr_in saddr;
saddr.sin_family=AF_INET;
saddr.sin_port=htons(8888); //设置端口
saddr.sin_addr.s_addr=inet_addr("192.168.31.109"); //点分十进制-》换成32位的网络字节序二进制值
int ret=bind(server_fd,(struct sockaddr *)&saddr,sizeof(saddr));
if(ret==-1)
{
perror("bind:");
return -1;
}
//设置监听套接字(设置同时来链接数)
ret=listen(server_fd,4); //server_fd设置为监听套接字
if(ret==-1)
{
perror("listen:");
return -1;
}
//等待对端链接
struct sockaddr_in client_buf;
socklen_t len = sizeof(client_buf);
int client_fd = accept(server_fd,(struct sockaddr *)&client_buf,&len); //成功返回对端的文件描述符
if(-1 == client_fd)
{
perror("accept:");
return -1;
}
//显示对端的ip和端口
printf("对端的ip为:%s\n",inet_ntoa(client_buf.sin_addr));
printf("对端的port为:%d\n",ntohs(client_buf.sin_port));
while(1)
{
//接收数据
char buffer1[20];
memset(buffer1,0,sizeof(buffer1));
// int len_rec = recv(client_fd,buffer1,sizeof(buffer1),0);
int len_rec = read(client_fd,buffer1,sizeof(buffer1));
if(len_rec > 0)
{
printf("客户端发来消息: %s\n",buffer1);
write(client_fd,buffer1,sizeof(buffer1));
}
if(len_rec == 0)
{
printf("连接断开\n");
break;
}
if(len_rec < 0)
{
perror("faile to read \n");
break;
}
}
/***********************
//文件操作
int fd=open("b.txt",O_RDWR | O_CREAT,0777);
if(-1 == fd)
{
printf("open err!\n");
return -1;
}
char buf[20] = {0};
while(1)
{
//第一题
// bzero(buf, 20);
// read(client_fd, buf, 20);
// printf("buf:%s\n", buf);
//第二题
bzero(buf, 20);
read(client_fd, buf, 20);
printf("buf:%s\n", buf);
if(!strcmp(buf, "exit"))
break;
write(fd,buf,strlen(buf));
}
*********************/
close(client_fd);
close(server_fd);
}
client代码
/**********
1、在服务器端接受消息时知道对方的IP和端口
提示:
bind出现:Address already in use 方法:netstat -nap查看 用kill -9 pid杀死
2、利用TCP实现文件传输
**********/
#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <strings.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include<stdlib.h>//
#include<netinet/in.h>//
#include<errno.h>
int main(void)
{
//建立套接字
int client_fd = socket(AF_INET, SOCK_STREAM, 0);
if(-1 == client_fd)
{
perror("socket");
return -1;
}
//链接服务器
struct sockaddr_in saddr;
bzero(&saddr, sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_port = htons(8888);
saddr.sin_addr.s_addr = inet_addr("192.168.31.109");
int ret = connect(client_fd, (struct sockaddr *)&saddr, sizeof(saddr));
if(-1 == ret)
{
perror("connect");
return -1;
}
int number =1;
while(1)
{
//发送数据
char buffer1[20];
sprintf(buffer1,"hi: %d",number++);
send(client_fd,buffer1,strlen(buffer1)+1,0);
//接收数据
memset(buffer1,0,20);
int len_rec = recv(client_fd,buffer1,sizeof(buffer1),0);
if(len_rec > 0)
{
printf("接收到服务器:%s\n",buffer1);
}
if(len_rec == 0)
{
printf("连接断开\n");
break;
}
if(len_rec < 0)
{
perror("faile to read \n");
break;
}
sleep(1);
}
/***
//文件操作
int fd=open("a.txt",O_RDWR | O_CREAT,0777);
if(-1 == fd)
{
printf("open err!\n");
return -1;
}
char fd_buf[20]={0};
while(1)
{
bzero(fd_buf,20);
ret = read(fd, fd_buf, 20); //读文件到缓冲区
if(ret==0)
{
write(client_fd,"exit", 20);
break;
}
else
{
printf("fd_buf%s\n",fd_buf);
write(client_fd, fd_buf, 20);
}
**/
/*bzero(fd_buf, 20);
scanf("%s", fd_buf);
write(client_fd, fd_buf, 20);
printf("fd_buf:%s\n", fd_buf);
if(!strcmp(fd_buf, "exit"))
break;*/
//}
close(client_fd);
}
文本交互
server代码
/**********
1、在服务器端接受消息时知道对方的IP和端口
提示:
bind出现:Address already in use 方法:netstat -nap查看 用kill -9 pid杀死
Server端bind本机IP地址使用INADDR_ANY
2、利用TCP实现文件传输
**********/
#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <strings.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(void)
{
//建立套接字
int server_fd=socket(AF_INET,SOCK_STREAM,0);
if(server_fd==-1)
{
perror("socket:");
return -1;
}
//绑定本机的IP和端口
struct sockaddr_in saddr;
saddr.sin_family=AF_INET;
saddr.sin_port=htons(7777); //设置端口
saddr.sin_addr.s_addr=inet_addr("192.168.31.109"); //点分十进制-》换成32位的网络字节序二进制值
//这里的ip是服务端本机的ip
int ret=bind(server_fd,(struct sockaddr *)&saddr,sizeof(saddr));
if(ret==-1)
{
perror("bind:");
return -1;
}
//设置监听套接字(设置同时来链接数)
ret=listen(server_fd,4); //server_fd设置为监听套接字
if(ret==-1)
{
perror("listen:");
return -1;
}
//等待对端链接
struct sockaddr_in client_buf;
socklen_t len = sizeof(client_buf);
int client_fd = accept(server_fd,(struct sockaddr *)&client_buf,&len); //成功返回对端的文件描述符
if(-1 == client_fd)
{
perror("accept:");
return -1;
}
//显示对端的ip和端口
printf("对端的ip为:%s\n",inet_ntoa(client_buf.sin_addr));
printf("对端的port为:%d\n",ntohs(client_buf.sin_port));
//文件操作
int fd=open("b.txt",O_RDWR | O_CREAT,0777);
if(-1 == fd)
{
printf("open err!\n");
return -1;
}
char buf[20] = {0};
while(1)
{
//第一题
/*bzero(buf, 20);
read(client_fd, buf, 20);
printf("buf:%s\n", buf);
*/
//第二题
bzero(buf, 20);
read(client_fd, buf, 20);
printf("buf:%s\n", buf);
if(!strcmp(buf, "exit"))
break;
write(fd,buf,strlen(buf));
}
close(client_fd);
close(server_fd);
}
client代码
/**********
1、在服务器端接受消息时知道对方的IP和端口
提示:
bind出现:Address already in use 方法:netstat -nap查看 用kill -9 pid杀死
2、利用TCP实现文件传输
**********/
#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <strings.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(void)
{
//建立套接字
int client_fd = socket(AF_INET, SOCK_STREAM, 0);
if(-1 == client_fd)
{
perror("socket");
return -1;
}
//链接服务器
struct sockaddr_in saddr;
bzero(&saddr, sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_port = htons(7777);
saddr.sin_addr.s_addr = inet_addr("192.168.31.109");
int ret = connect(client_fd, (struct sockaddr *)&saddr, sizeof(saddr));
if(-1 == ret)
{
perror("connect");
return -1;
}
//文件操作
int fd=open("a.txt",O_RDWR | O_CREAT,0777);
if(-1 == fd)
{
printf("open err!\n");
return -1;
}
char fd_buf[20]={0};
while(1)
{
bzero(fd_buf,20);
ret = read(fd, fd_buf, 20); //读文件到缓冲区
if(ret==0)
{
write(client_fd,"exit", 20);
break;
}
else
{
printf("fd_buf%s\n",fd_buf);
write(client_fd, fd_buf, 20);
}
/*bzero(fd_buf, 20);
scanf("%s", fd_buf);
write(client_fd, fd_buf, 20);
printf("fd_buf:%s\n", fd_buf);
if(!strcmp(fd_buf, "exit"))
break;*/
}
close(client_fd);
}
遇到的问题
1.Connection refused: connect服务端没有开启
2.gcc指令使用错误示范:gcc -c server.c -o server.out
,加-c
是不对的。
3.bind函数出现Cannot assign requested address
方法一:通过netstat -nap查看当前的状态,的确看到很多TIME_WAIT状态的连接。可以通过pid 用命令 kill -9 pid,杀死处于TIME_WAIT状态的进程。
问题二:因为我的测试是以window当服务器,Ubuntu当客户端,所以需要用到桥接技术,让两个系统在一个网段里面。那么出现bind的错误很有可能是你的网络的问题。我自己在测试的时候,试了很多种方法,还能ping通,但是网络这一块还是有点问题,还是出现bind错误。
import socket
#创建服务端的socket对象socketserver
socketserver = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = "192.168.31.24"
port = 8000
#绑定地址(包括ip地址会端口号)
socketserver.bind((host, port))
#设置监听
socketserver.listen(5)
#等待客户端的连接
#注意:accept()函数会返回一个元组
#元素1为客户端的socket对象,元素2为客户端的地址(ip地址,端口号)
clientsocket,addr = socketserver.accept()
#while循环是为了能让对话一直进行,直到客户端输入q
while True:
#接收客户端的请求
recvmsg = clientsocket.recv(1024)
#把接收到的数据进行解码
strData = recvmsg.decode("utf-8")
#判断客户端是否发送q,是就退出此次对话
if strData=='q':
break
print("收到:"+strData)
msg = input("回复:")
#对要发送的数据进行编码
clientsocket.send(msg.encode("utf-8"))
import socket
#创建一个客户端的socket对象
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#设置服务端的ip地址
host = "192.168.31.24"
#设置端口
port = 8000
#连接服务端
client.connect((host, port))
#while循环是为了保证能持续进行对话
while True:
#输入发送的消息
sendmsg = input("请输入:")
#如果客户端输入的是q,则停止对话并且退出程序
if sendmsg=='q':
break
sendmsg = sendmsg
#发送数据,以二进制的形式发送数据,所以需要进行编码
client.send(sendmsg.encode("utf-8"))
msg = client.recv(1024)
#接收服务端返回的数据,需要解码
print(msg.decode("utf-8"))
#关闭客户端
client.close()
4.Cannot assign requested address解决办法
链接: Cannot assign requested address
多线程
以下是完整的多线程客户端和服务器端的代码示例:
-lpthread
服务器端代码(server.c):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <pthread.h>
#define PORT 8080
#define MAX_BUFFER_SIZE 1024
void *client_handler(void *arg)
{
int client_sock = *((int *)arg);
char buffer[MAX_BUFFER_SIZE];
ssize_t bytes_received;
// 接收数据
while ((bytes_received = recv(client_sock, buffer, sizeof(buffer) - 1, 0)) > 0) {
buffer[bytes_received] = '\0';
printf("Received from client: %s\n", buffer);
// 处理数据(这里可以根据业务需求进行相应的操作)
// 发送数据
char *response = "Hello from server";
ssize_t bytes_sent = send(client_sock, response, strlen(response), 0);
if (bytes_sent == -1) {
perror("Failed to send data");
exit(EXIT_FAILURE);
}
}
if (bytes_received == 0) {
printf("Client disconnected\n");
} else if (bytes_received == -1) {
perror("Failed to receive data");
exit(EXIT_FAILURE);
}
// 关闭套接字
close(client_sock);
free(arg);
pthread_exit(NULL);
}
int main()
{
int server_sock, client_sock;
struct sockaddr_in server_addr, client_addr;
socklen_t client_addr_len = sizeof(client_addr);
pthread_t tid;
// 创建套接字
server_sock = socket(AF_INET, SOCK_STREAM, 0);
if (server_sock < 0) {
perror("Failed to create socket");
exit(EXIT_FAILURE);
}
// 设置服务器的地址和端口
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(PORT);
// 绑定套接字
if (bind(server_sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
perror("Failed to bind");
exit(EXIT_FAILURE);
}
// 监听端口
if (listen(server_sock, 5) < 0) {
perror("Failed to listen");
exit(EXIT_FAILURE);
}
printf("Server started. Listening on port %d\n", PORT);
// 接受连接并创建独立线程进行通信
while ((client_sock = accept(server_sock, (struct sockaddr *)&client_addr, &client_addr_len))) {
printf("Client connected: %s\n", inet_ntoa(client_addr.sin_addr));
// 为每个连接创建一个新的线程
int *new_sock = malloc(sizeof(int));
*new_sock = client_sock;
if (pthread_create(&tid, NULL, client_handler, (void *)new_sock) != 0) {
perror("Failed to create thread");
exit(EXIT_FAILURE);
}
// 分离线程,使其自行清理退出
//pthread_detach(tid);
if (pthread_detach(tid) != 0)
{
perror("Failed to detach thread");
exit(EXIT_FAILURE);
}
}
if (client_sock < 0) {
perror("Failed to accept");
exit(EXIT_FAILURE);
}
// 关闭套接字
close(server_sock);
return 0;
}
客户端代码(client.c):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#define SERVER_IP "127.0.0.1"
#define PORT 8080
#define MAX_BUFFER_SIZE 1024
int main()
{
int sock;
struct sockaddr_in server_addr;
// 创建套接字
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
perror("Failed to create socket");
exit(EXIT_FAILURE);
}
// 设置服务器的地址和端口
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(PORT);
if (inet_pton(AF_INET, SERVER_IP, &server_addr.sin_addr) <= 0) {
perror("Failed to set server address");
exit(EXIT_FAILURE);
}
// 连接到服务器
if (connect(sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
perror("Failed to connect to server");
exit(EXIT_FAILURE);
}
// 发送和接收数据
char buffer[MAX_BUFFER_SIZE];
memset(buffer, 0, sizeof(buffer));
// 发送数据
sprintf(buffer, "Hello from client");
ssize_t bytes_sent = send(sock, buffer, strlen(buffer), 0);
if (bytes_sent == -1) {
perror("Failed to send data");
exit(EXIT_FAILURE);
}
// 接收数据
ssize_t bytes_received = recv(sock, buffer, sizeof(buffer) - 1, 0);
if (bytes_received == -1) {
perror("Failed to receive data");
exit(EXIT_FAILURE);
}
buffer[bytes_received] = '\0'; // 添加字符串结束符
printf("Received: %s\n", buffer);
// 关闭套接字
close(sock);
return 0;
}
请确保在编译时使用-lpthread
选项链接pthread
库。编译和运行这两个程序后,可以通过启动多个客户端并与服务器建立连接,观察多个客户端同时与服务器进行通信。
优化
以下是优化后的服务端程序,按照您的要求更新了代码并添加了IP记录:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <pthread.h>
#define PORT 8080
#define MAX_BUFFER_SIZE 1024
void *client_handler(void *arg)
{
int client_sock = *((int *)arg);
char buffer[MAX_BUFFER_SIZE];
ssize_t bytes_received;
char client_ip[INET_ADDRSTRLEN];
struct sockaddr_in client_addr;
socklen_t addr_len = sizeof(client_addr);
// 获取客户端 IP 地址
getpeername(client_sock, (struct sockaddr*)&client_addr, &addr_len);
inet_ntop(AF_INET, &(client_addr.sin_addr), client_ip, INET_ADDRSTRLEN);
printf("New client connected from %s in thread %lu\n", client_ip, pthread_self());
FILE *file;
char filename[INET_ADDRSTRLEN + 5]; // IP 地址作为文件名
sprintf(filename, "%s.txt", client_ip);
// 接收数据
while ((bytes_received = recv(client_sock, buffer, sizeof(buffer) - 1, 0)) > 0) {
buffer[bytes_received] = '\0';
printf("Received from client %s: %s\n", client_ip, buffer);
// 保存收发记录到文件
file = fopen(filename, "a");
if (file != NULL) {
fprintf(file, "Received: %s\n", buffer);
fclose(file);
}
// 发送数据
char *response = "Hello from server";
ssize_t bytes_sent = send(client_sock, response, strlen(response), 0);
if (bytes_sent == -1) {
perror("Failed to send data");
exit(EXIT_FAILURE);
}
// 保存收发记录到文件
file = fopen(filename, "a");
if (file != NULL) {
fprintf(file, "Sent: %s\n", response);
fclose(file);
}
}
if (bytes_received == 0) {
printf("Client %s disconnected\n", client_ip);
} else if (bytes_received == -1) {
perror("Failed to receive data");
exit(EXIT_FAILURE);
}
// 关闭套接字
close(client_sock);
free(arg);
pthread_exit(NULL);
}
int main()
{
int server_sock, client_sock;
struct sockaddr_in server_addr, client_addr;
socklen_t client_addr_len = sizeof(client_addr);
pthread_t tid;
// 创建套接字
server_sock = socket(AF_INET, SOCK_STREAM, 0);
if (server_sock < 0) {
perror("Failed to create socket");
exit(EXIT_FAILURE);
}
// 设置服务器的地址和端口
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(PORT);
// 绑定套接字
if (bind(server_sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
perror("Failed to bind");
exit(EXIT_FAILURE);
}
// 监听端口
if (listen(server_sock, 5) < 0) {
perror("Failed to listen");
exit(EXIT_FAILURE);
}
printf("Server started. Listening on port %d\n", PORT);
// 接受连接并创建独立线程进行通信
while ((client_sock = accept(server_sock, (struct sockaddr *)&client_addr, &client_addr_len))) {
// 为每个连接创建一个新的线程
int *new_sock = malloc(sizeof(int));
*new_sock = client_sock;
if (pthread_create(&tid, NULL, client_handler, (void *)new_sock) != 0) {
perror("Failed to create thread");
exit(EXIT_FAILURE);
}
// 让线程自行清理退出
pthread_detach(tid);
}
if (client_sock < 0) {
perror("Failed to accept");
exit(EXIT_FAILURE);
}
// 关闭套接字
close(server_sock);
return 0;
}
在优化后的服务端程序中,新增了记录客户端IP收发数据的功能,并将不同IP的记录保存到对应的文件中。同时,还添加打印新加入的线程号以及对应的IP的功能。这样,每次客户端连接时,都会打印新连接的IP地址和线程号,并将收发数据的记录保存到以IP地址命名的文本文件中。
优化2
以下是优化后的服务端程序,按照您的要求更新了代码并添加了时间记录:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <pthread.h>
#include <time.h>
#define PORT 8080
#define MAX_BUFFER_SIZE 1024
void *client_handler(void *arg) {
int client_sock = *((int *)arg);
char buffer[MAX_BUFFER_SIZE];
ssize_t bytes_received;
char client_ip[INET_ADDRSTRLEN];
struct sockaddr_in client_addr;
socklen_t addr_len = sizeof(client_addr);
// 获取客户端 IP 地址
getpeername(client_sock, (struct sockaddr*)&client_addr, &addr_len);
inet_ntop(AF_INET, &(client_addr.sin_addr), client_ip, INET_ADDRSTRLEN);
printf("New client connected from %s in thread %lu\n", client_ip, pthread_self());
FILE *file;
char filename[INET_ADDRSTRLEN + 5]; // IP 地址作为文件名
sprintf(filename, "%s.txt", client_ip);
// 接收数据
while ((bytes_received = recv(client_sock, buffer, sizeof(buffer) - 1, 0)) > 0) {
buffer[bytes_received] = '\0';
printf("Received from client %s: %s\n", client_ip, buffer);
// 获取当前时间
time_t now;
struct tm *local_time;
char time_buffer[20];
now = time(NULL);
local_time = localtime(&now);
strftime(time_buffer, sizeof(time_buffer), "%Y-%m-%d %H:%M:%S", local_time);
// 保存收发记录到文件
file = fopen(filename, "a");
if (file != NULL) {
fprintf(file, "[%s] Received: %s\n", time_buffer, buffer);
fclose(file);
}
// 发送数据
char *response = "Hello from server";
ssize_t bytes_sent = send(client_sock, response, strlen(response), 0);
if (bytes_sent == -1) {
perror("Failed to send data");
exit(EXIT_FAILURE);
}
// 保存收发记录到文件
file = fopen(filename, "a");
if (file != NULL) {
fprintf(file, "[%s] Sent: %s\n", time_buffer, response);
fclose(file);
}
}
if (bytes_received == 0) {
printf("Client %s disconnected\n", client_ip);
} else if (bytes_received == -1) {
perror("Failed to receive data");
exit(EXIT_FAILURE);
}
// 关闭套接字
close(client_sock);
free(arg);
pthread_exit(NULL);
}
int main() {
int server_sock, client_sock;
struct sockaddr_in server_addr, client_addr;
socklen_t client_addr_len = sizeof(client_addr);
pthread_t tid;
// 创建套接字
server_sock = socket(AF_INET, SOCK_STREAM, 0);
if (server_sock < 0) {
perror("Failed to create socket");
exit(EXIT_FAILURE);
}
// 设置服务器的地址和端口
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(PORT);
// 绑定套接字
if (bind(server_sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
perror("Failed to bind");
exit(EXIT_FAILURE);
}
// 监听端口
if (listen(server_sock, 5) < 0) {
perror("Failed to listen");
exit(EXIT_FAILURE);
}
printf("Server started. Listening on port %d\n", PORT);
// 接受连接并创建独立线程进行通信
while ((client_sock = accept(server_sock, (struct sockaddr *)&client_addr, &client_addr_len))) {
// 为每个连接创建一个新的线程
int *new_sock = malloc(sizeof(int));
*new_sock = client_sock;
if (pthread_create(&tid, NULL, client_handler, (void *)new_sock) != 0) {
perror("Failed to create thread");
exit(EXIT_FAILURE);
}
// 让线程自行清理退出
pthread_detach(tid);
}
if (client_sock < 0) {
perror("Failed to accept");
exit(EXIT_FAILURE);
}
// 关闭套接字
close(server_sock);
return 0;
}
在优化后的服务端程序中,根据您的要求,新增了记录收发数据内容和时间的功能,并将其保存到以IP地址命名的文本文件中。每次收到数据时,程序会获取当前时间并将时间、收到的数据和发送的响应一起记录到文本文件中。
注意,这里使用了C标准库中的time
和localtime
函数来获取当前时间,并使用strftime
函数将时间格式化为字符串。同时,程序在记录文件时也添加了时间前缀,以便于后续查看记录时进行时间标注。
优化客户端
以下是优化后的客户端程序,根据您的要求更新了代码,并添加了打印收发数据和保存到文本文件的功能:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netdb.h>
#include <time.h>
#define PORT 8080
#define MAX_BUFFER_SIZE 1024
void save_to_file(const char *filename, const char *data) {
FILE *file;
time_t now;
struct tm *local_time;
char time_buffer[20];
now = time(NULL);
local_time = localtime(&now);
strftime(time_buffer, sizeof(time_buffer), "%Y-%m-%d %H:%M:%S", local_time);
file = fopen(filename, "a");
if (file != NULL) {
fprintf(file, "[%s] %s\n", time_buffer, data);
fclose(file);
}
}
int main() {
int client_sock;
struct sockaddr_in server_addr;
char *server_ip = "127.0.0.1"; // 服务器的 IP 地址
char buffer[MAX_BUFFER_SIZE];
ssize_t bytes_received;
char server_response[MAX_BUFFER_SIZE];
// 创建套接字
client_sock = socket(AF_INET, SOCK_STREAM, 0);
if (client_sock < 0) {
perror("Failed to create socket");
exit(EXIT_FAILURE);
}
// 设置服务器的地址和端口
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr(server_ip);
server_addr.sin_port = htons(PORT);
// 连接到服务器
if (connect(client_sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
perror("Failed to connect");
exit(EXIT_FAILURE);
}
printf("Connected to server %s\n", server_ip);
// 接收和发送数据
while (1) {
printf("Enter message: ");
fgets(buffer, sizeof(buffer), stdin);
buffer[strcspn(buffer, "\n")] = '\0';
// 保存发送的数据到文件
save_to_file("client.log", buffer);
// 发送数据
ssize_t bytes_sent = send(client_sock, buffer, strlen(buffer), 0);
if (bytes_sent == -1) {
perror("Failed to send data");
exit(EXIT_FAILURE);
}
// 接收数据
bytes_received = recv(client_sock, server_response, sizeof(server_response) - 1, 0);
if (bytes_received == -1) {
perror("Failed to receive data");
exit(EXIT_FAILURE);
} else if (bytes_received == 0) {
break; // 退出循环,断开连接
}
server_response[bytes_received] = '\0';
printf("Server response: %s\n", server_response);
// 保存接收的数据到文件
save_to_file("client.log", server_response);
}
// 关闭套接字
close(client_sock);
return 0;
}
在优化后的客户端程序中,根据您的要求,新增了打印收发数据和保存到文本文件的功能。每次发送数据时,程序会将发送的数据通过 save_to_file
函数保存到名为 “client.log” 的文本文件中。同时,程序在接收到服务器响应时,也会将响应通过 save_to_file
函数保存到相同的文本文件中。
save_to_file
函数会获取当前时间,并将时间、收发的数据作为日志记录保存到文件中。
HTML客户端
以下是一个简单的示例代码,演示了如何在网页上使用 WebSocket 与 Python 服务器进行通信。在这个示例中,我们将使用 JavaScript 的 WebSocket API 来实现客户端的交互,以及 Python 的 websockets
模块来实现服务器端的通信。
server.py (Python WebSocket 服务器)
import asyncio
import websockets
async def echo(websocket, path):
async for message in websocket:
print(f"Received message: {message}")
# 对接收的消息进行处理
await websocket.send(f"Server received your message: {message}")
start_server = websockets.serve(echo, "localhost", 8765)
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()
错误提示显示缺少名为 ‘websockets’ 的模块,这意味着你需要在你的 Python 环境中安装 websockets
模块。你可以通过以下步骤来安装该模块:
-
确保你的系统已经安装了 Python3。你可以在终端输入以下命令验证:
python3 --version
-
使用以下命令安装
websockets
模块:pip3 install websockets
如果你的系统没有安装 pip3,你需要先安装 pip3,具体方式取决于你的操作系统发行版。在大多数情况下,你可以使用以下命令来安装 pip3:
sudo apt-get install python3-pip
-
安装完成后,再次运行
python3 server.py
命令。现在应该可以正常启动服务器了。
如果你遇到了其他问题或有其他疑问,请告诉我。
index.html (网页端)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WebSocket Communication</title>
</head>
<body>
<textarea id="receiveText" cols="50" rows="10"></textarea><br>
<input id="sendText" type="text" size="50"><br>
<button id="sendButton">发送</button>
<script>
const webSocket = new WebSocket('ws://localhost:8765');
webSocket.onopen = function(event) {
console.log("WebSocket连接已打开");
};
webSocket.onmessage = function(event) {
console.log("接收到消息: " + event.data);
// 将消息显示在接收文本框中
const receiveText = document.getElementById('receiveText');
receiveText.value += event.data + '\n';
};
const sendButton = document.getElementById('sendButton');
sendButton.addEventListener('click', function() {
// 获取发送文本框中的值
const sendText = document.getElementById('sendText').value;
// 发送消息到服务器
webSocket.send(sendText);
// 清空发送文本框
document.getElementById('sendText').value = '';
});
</script>
</body>
</html>
在这个示例中,Python 服务器使用了 websockets
模块创建了一个 WebSocket 服务器,它在本地的 8765 端口上进行监听。当有消息传入时,服务器会回显消息并发送回客户端。在网页端的 JavaScript 代码中,我们首先创建了一个 WebSocket 对象,它连接到指定的服务器地址和端口。同时我们为 WebSocket 对象设置了 onopen
和 onmessage
事件处理函数,以处理连接建立和消息接收的逻辑。当用户点击发送按钮时,发送文本框中的文本将被发送到服务器端。