socket网络编程——服务器端

  1. 创建Socket:使用Socket函数创建Socket套接字,可以指定TCP或UDP协议。
  2. 监听连接:在服务器端,使用bind函数绑定IP地址和端口,然后使用listen函数开始监听连接请求。
  3. 接受连接:在服务器端使用accept函数接受客户端的连接请求,并返回一个新的套接字进行通信。
  4. 建立连接:在客户端,使用connect函数连接服务器,并返回一个新的套接字进行通信。
  5. 数据传输:在建立好连接后,进行数据的发送和接收。
  6. 关闭连接:在通信结束后,使用close函数关闭套接字。

 server.c

/*************************************************************************
 > File Name: server.c
 > Author: licz
 > Created Time: Sun 10 Sep 2023 01:47:01 PM CST
 ************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <unistd.h>
#include <time.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

#define BUFFER_SIZE 1024
void displayWithTimestamp(const char* format, ...);
void printClientInfo(int clientSocket);
int main() {
    int sockfd, newsockfd, portno;
    socklen_t clilen;
    char buffer[BUFFER_SIZE],client_ip[1024];
    struct sockaddr_in serv_addr, cli_addr;
    int n;
	displayWithTimestamp("Waiting for the socket connection to be established ...");
    // 创建套接字,其中 AF_INET 表示使用 IPv4 地址族,SOCK_STREAM 表示使用 TCP 协议进行通信。
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) {
        perror("Error opening socket");
        exit(1);
    }
    displayWithTimestamp("Socket connection established successfully !");
    
    // 初始化服务器地址结构
    memset((char *)&serv_addr, 0, sizeof(serv_addr));
    portno = 8848; // 设置监听的端口号
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    serv_addr.sin_port = htons(portno);//将端口号转换为网络字节序

    // 绑定套接字到指定端口
    if (bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
        perror("Error on binding");
        exit(1);
    }

    // 开始监听连接请求
    listen(sockfd, 5);//将套接字设置为监听状态,并指定最大允许的连接数。
    clilen = sizeof(cli_addr);
	
    // 接受客户端连接
    
    displayWithTimestamp("Wait for a client connection to be established...");
    newsockfd = accept(sockfd, (struct sockaddr *)&cli_addr, &clilen);
    if (newsockfd < 0) {
        perror("Error on accept");
        exit(1);
    }
	displayWithTimestamp("Client established successfully !");
	printClientInfo(newsockfd);
    // 打开文件用于保存数据
    FILE *file = fopen("data.txt", "w");
    if (file == NULL) {
        perror("Error opening file");
        exit(1);
    }

    // 接收数据并保存到文件
    while ((n = read(newsockfd, buffer, BUFFER_SIZE)) > 0) {
        fwrite(buffer, sizeof(char), n, file); // 写入文件
        displayWithTimestamp("%s",buffer); // 打印到终端
        memset(buffer, 0, BUFFER_SIZE); // 清空缓冲区
    }

    // 关闭文件和套接字
    fclose(file);
    close(newsockfd);
    close(sockfd);

    return 0;
}

void printClientInfo(int clientSocket) {
    struct sockaddr_in clientAddress;
    socklen_t clientAddressLength = sizeof(clientAddress);

    // 获取客户端地址信息
    if (getpeername(clientSocket, (struct sockaddr*)&clientAddress, &clientAddressLength) < 0) {
        perror("获取客户端地址信息失败");
        exit(EXIT_FAILURE);
    }

    char clientIP[INET_ADDRSTRLEN];
    if (inet_ntop(AF_INET, &(clientAddress.sin_addr), clientIP, INET_ADDRSTRLEN) == NULL) {
        perror("获取客户端IP地址失败");
        exit(EXIT_FAILURE);
    }

    displayWithTimestamp("连接来自 %s:%d\n", clientIP, ntohs(clientAddress.sin_port));
}

void displayWithTimestamp(const char* format, ...) {
    // 获取当前时间戳
    time_t currentTime;
    time(&currentTime);

    // 转换为本地时间结构
    struct tm* localTime = localtime(&currentTime);

    // 格式化时间戳
    char timestampString[20];
    strftime(timestampString, sizeof(timestampString), "%Y-%m-%d %H:%M:%S", localTime);

    // 打印带有时间戳的信息
    printf("[%s] ", timestampString);

    // 使用可变参数列表打印消息内容
    va_list args;
    va_start(args, format);
    vprintf(format, args);
    va_end(args);

    printf("\n");
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jay-juice

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值