socket传出json格式报文

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;

import net.sf.json.JSONObject;

public class Server_2 {
    public static void main(String[] args) {
        Scanner in=new Scanner(System.in);
        InputStreamReader isr;
        BufferedReader br;
        OutputStreamWriter osw;
        BufferedWriter rw;

        try {
            ServerSocket serverSocket=new ServerSocket(4444);
            Socket socket=serverSocket.accept();
            isr=new InputStreamReader(socket.getInputStream());
            br=new BufferedReader(isr);
            String str=br.readLine();
            JSONObject object=JSONObject.fromObject(str);
            System.out.println("ID:"+object.getInt("ID"));
            System.out.println("Name:"+object.getString("name"));
            System.out.println("password:"+object.getString("password"));
            br.close();
            socket.close();
            serverSocket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

客服端

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.Scanner;

import net.sf.json.JSONObject;

public class Client_2 {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        InputStreamReader isr;
        BufferedReader br;
        OutputStreamWriter osw;
        BufferedWriter rw;
        try {
            Socket socket = new Socket("localhost", 4444);
            osw = new OutputStreamWriter(socket.getOutputStream());
            rw = new BufferedWriter(osw);
            User user = new User();
            System.out.println("Id:");
            user.setID(in.nextInt());
            in.nextLine();
            System.out.println("Name:");
            user.setName(in.nextLine());
            System.out.println("Password:");
            user.setPassword(in.nextLine());
            JSONObject jsonObject = JSONObject.fromObject(user);
            rw.write(jsonObject.toString()+"\n");
            rw.close();
            socket.close();
        } catch (Exception e) {
            // TODO: handle exception
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

User


public class User {
    int ID;
    String name;
    String password;
    public int getID() {
        return ID;
    }
    public void setID(int iD) {
        ID = iD;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.youkuaiyun.com/qq_14949289/article/details/49272175
/* * @copyright: copyright (c) 2025 Chengdu TP-Link Technologies Co.Ltd. * @fileName: server.h * @description: function declaration file of server.c * @Author: Wang ZHiheng * @email: wangzhiheng@tp-link.com.hk * @version: 1.0.0 * @Date: 2025-08-07 * @history: \arg 1.0.0, 25Aug07, Wang Zhiheng, Create the file */ #include <arpa/inet.h> #include <sys/epoll.h> #include <pthread.h> #include <stdio.h> #include <errno.h> #include <unistd.h> #include <strings.h> #include <string.h> #include <sys/stat.h> #include <sys/sendfile.h> #include <dirent.h> #include <stdlib.h> #include <pthread.h> #include <ctype.h> #include <fcntl.h> #include <math.h> #include "server.h" /* 函数声明文件 */ /* 错误处理 */ #define handle_error(cmd, result) \ if (result < 0) \ { \ perror(cmd); \ return -1; \ } /** * @function: int init_listen_fd(unsigned short port) * @description: 新建一个用于TCP监听的socket文件描述符,并返回 * @return 返回监听socket的文件描述符 * @note: * @param {unsigned short} port 监听端口号 */ int init_listen_fd(unsigned short port) { int listen_sockfd; /* 监听socket */ struct sockaddr_in listen_addr; /* 监听地址 */ memset(&listen_addr, 0, sizeof(listen_addr)); /* 初始化 */ int temp_result; /* 存储临时变量用于debug */ /* 创建监听socket */ listen_sockfd = socket(AF_INET, SOCK_STREAM, 0); handle_error("socket", listen_sockfd); /* 设置端口复用 */ int opt = -1; int ret = setsockopt(listen_sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof opt); handle_error("setsockopt", listen_sockfd); /* 绑定端口和IP */ listen_addr.sin_family = AF_INET; listen_addr.sin_addr.s_addr = INADDR_ANY; listen_addr.sin_port = htons(port); /* 绑定地址 */ temp_result = bind(listen_sockfd, (struct sockaddr *)&listen_addr, sizeof(listen_addr)); handle_error("bind", temp_result); printf("bind success\n"); /* 进入监听模式 */ if (listen(listen_sockfd, 128) < 0) { perror("listen failed"); close(listen_sockfd); exit(EXIT_FAILURE); } printf("listen success\n"); return listen_sockfd; } /** * @function: int epoll_run(int listen_sockfd) * @description: 启动epoll * @return 返回值无实际作用,因为会处于循环状态监听 * @note: * @param {int} listen_sockfd 监听socket的文件描述符 */ int threads_run(int listen_sockfd) { int temp_result; /* 存储临时变量用于debug */ struct sockaddr_in client_addr; /* 用于存储客户端地址 */ memset(&client_addr, 0, sizeof(client_addr)); /* 接收client连接 */ socklen_t client_addr_len = sizeof(client_addr); while (1) { pthread_t pid; /* 子线程, 用于从客户端读取数据*/ int *client_fd_ptr = (int *)malloc(sizeof(int)); int client_fd = accept(listen_sockfd, (struct sockaddr *)&client_addr, &client_addr_len); *client_fd_ptr = client_fd; if (client_fd < 0) { perror("accept failed"); close(listen_sockfd); exit(EXIT_FAILURE); } printf("a client from ip:%s at port %d, socket %d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port), client_fd); /* 调用子线程接收客户端数据, 并发送响应*/ if ((pthread_create(&pid, NULL, recv_http_request, client_fd_ptr)) != 0) { // perror("pthread_create"); // pthread_exit(&pid); perror("pthread_create failed"); close(client_fd); free(client_fd_ptr); continue; } /* 使子线程处于detached状态,使其终止时自动回收资源,同时不阻塞线程 */ // pthread_join(pid, NULL); pthread_detach(pid); } printf("close socket"); close(listen_sockfd); return 0; } /** * @function: void* recv_http_request(void* arg) * @description: 接收http请求, 读取数据 * @return * @note: conn_fd表示连接socket, epoll_fd表示epoll树 * @param {void*} arg */ void *recv_http_request(void *arg) { printf("进入recv\n"); int client_fd = *(int *)arg; int len = 0; /* 用于接收recv的返回值 */ char buf[4096] = {0}; /* 接收客户端请求数据 */ len = recv(client_fd, buf, sizeof(buf), 0); if (len <= 0) { printf("Client disconnected\n"); close(client_fd); free(arg); return NULL; } printf("len%d\n", len); parse_request(buf, (int *)arg); free(arg); printf("退出 recv\n"); close(client_fd); } /** * @function: int parse_request(const char *line, int conn_fd) * @description: 解析HTTP的请求行,并调用send_http_response * @return {*} * @note: * @param {char} *line * @param {int} conn_fd */ int parse_request(const char *message, int *conn_fd) { /* 解析请求行 */ char method[12]; /* 存储客户端请求方法,如GET/POST */ char path[1024]; char *filename = NULL; /* 处理客户端请求的静态资源(目录或文件) */ char version[1024]; printf("获取方法和路径\n"); sscanf(message, "%s %s %s", method, path, version); printf("请求内容: \nmethod:%s, path:%s\n\n", method, path); /* 不区分大小写的比较,如果不等于0,则返回-1 */ if (strcasecmp(method, "get") == 0) { /* 处理客户端请求的静态资源(目录或文件),因为当前获得的/xxx/1.jpg是相对于工作路径的,所以需要转换为./xxx/1.jpg或者xxx/1.jpg */ if (strcmp(path, "/") == 0) { /* 如果get当前的工作目录 */ filename = "./"; } else { filename = path + 1; /* get工作目录中的一个资源 */ } send_http_response(*conn_fd, filename); } else if(strcasecmp(method, "post") == 0) { // 检查是否为前端指定的 /data/contact.json 路径 if (strcmp(path, "/data/contact.json") == 0) { // 查找请求体起始位置 const char *body_start = strstr(message, "\r\n\r\n"); if (body_start) { body_start += 4; // 跳过空行 // 解析表单数据 (application/x-www-form-urlencoded) char *name = NULL, *email = NULL, *message_content = NULL; char *token = strtok((char *)body_start, "&"); while (token != NULL) { if (strstr(token, "name=") == token) { name = token + 5; // 跳过 "name=" } else if (strstr(token, "email=") == token) { email = token + 6; // 跳过 "email=" } else if (strstr(token, "message=") == token) { message_content = token + 8; // 跳过 "message=" } token = strtok(NULL, "&"); } // 打印解码后的表单数据 printf("收到联系表单数据:\n"); printf("姓名: %s\n", url_decode(name)); printf("邮箱: %s\n", url_decode(email)); printf("留言: %s\n", url_decode(message_content)); // 发送前端期望的JSON响应 const char *response = "HTTP/1.1 200 OK\r\n" "Content-Type: application/json\r\n" "Content-Length: 27\r\n" "Connection: close\r\n" "\r\n" "{\"callback\":\"提交成功\"}"; send(*conn_fd, response, strlen(response), 0); } else { // 没有找到请求体 const char *response = "HTTP/1.1 400 Bad Request\r\n" "Content-Type: application/json\r\n" "Content-Length: 39\r\n" "Connection: close\r\n" "\r\n" "{\"error\":\"请求体缺失\"}"; send(*conn_fd, response, strlen(response), 0); } } } else { return -1; } return 0; } /** * @function: void send_http_response(int sockfd, const char* file_path) * @description: 发送http响应报文, 包括 响应头 响应文件数据 等 * @return * @note: * @param {int*} sockfd 与客户端连接的socket文件描述符 * @param {char*} file_path 需要发送的文件路径 */ void send_http_response(int sockfd, const char *file_path) { struct stat file_stat; /* stat函数的传出采纳数 */ char buffer[(int)pow(2, 17)]; /* 用于读取文件和发送数据的缓冲区 */ ssize_t bytes_read; /* 用于接收read返回的数据长度 */ if (stat(file_path, &file_stat) != 0) { /* 文件不存在或无法获取状态 */ const char *response_404 = "HTTP/1.1 404 Not Found\r\n" "Content-Type: text/html\r\n" "Content-Length: 133\r\n" "Connection: close\r\n" "\r\n" "<html><body><h1>404 Not Found</h1><p>The requested file was not found on this server.</p></body></html>"; send(sockfd, response_404, strlen(response_404), 0); close(sockfd); return; } int fd = open(file_path, O_RDONLY); if (fd == -1) { /* 打开文件失败 */ const char *response_500 = "HTTP/1.1 500 Internal Server Error\r\n" "Content-Type: text/html\r\n" "Content-Length: 151\r\n" "Connection: close\r\n" "\r\n" "<html><body><h1>500 Internal Server Error</h1><p>Failed to open the requested file.</p></body></html>"; send(sockfd, response_500, strlen(response_500), 0); close(sockfd); return; } printf("打开文件%s\n", file_path); const char *mime_type = get_mime_type(file_path); /* 发送HTTP响应头 */ char response_header[2048]; snprintf(response_header, sizeof(response_header), "HTTP/1.1 200 OK\r\n" "Content-Type: %s\r\n" "Content-Length: %ld\r\n" "Connection: keep-alive\r\n" "\r\n", mime_type, file_stat.st_size); send(sockfd, response_header, strlen(response_header), 0); /* 循环读取并发送文件内容 */ while ((bytes_read = read(fd, buffer, sizeof(buffer))) > 0) { ssize_t sent = send(sockfd, buffer, bytes_read, 0); if (sent < 0) { perror("send failed"); break; } } printf("bytes_read: %zd\n", bytes_read); close(fd); /* 关闭文件描述符 */ } /** * @function: char *url_decode(const char *src) * @description: 将post请求解码为姓名、邮箱、留言三项 * @return * @note: * @param {int*} sockfd 与客户端连接的socket文件描述符 * @param {char*} file_path 需要发送的文件路径 */ char *url_decode(const char *src) { if (!src) return NULL; size_t src_len = strlen(src); char *decoded = malloc(src_len + 1); char *dst = decoded; while (*src) { if (*src == '+') { *dst++ = ' '; src++; } else if (*src == '%' && isxdigit(src[1]) && isxdigit(src[2])) { char hex[3] = {src[1], src[2], '\0'}; *dst++ = (char)strtol(hex, NULL, 16); src += 3; } else { *dst++ = *src++; } } *dst = '\0'; return decoded; } /** * @function: const char* get_mime_type(const char* filename) * @description: MIME类型映射, 获取发送给客户端文件名称的后缀名, 以生成对应Content-Type参数 * @return 返回存储Content-Type参数的指针 * @note: 根据提供的web页面, 只涉及了其中三种Content-Type参数 * @param {char*} filename 要发送给客户端的路径名或文件名 */ const char *get_mime_type(const char *filename) { const char *dot = NULL; /* 接收strrchr返回参数,存储文件后缀名 */ dot = strrchr(filename, '.'); /* strrchr获取指定字符的最后一次出现 */ /* 根据文件后缀名生成对应Content-Type参数 */ if (dot == NULL) return "application/octet-stream"; if (strcmp(dot, ".html") == 0 || strcmp(dot, ".htm") == 0) return "text/html"; else if (strcmp(dot, ".css") == 0) return "text/css"; else if (strcmp(dot, ".png") == 0 || strcmp(dot, ".jpg") == 0 || strcmp(dot, ".jpeg") == 0) return "image/jpeg"; /* 注意:这里为了简化,JPEG和PNG都使用了image/jpeg,实际应分开处理 */ return "application/octet-stream"; } 没有问题了,不改代码,就统一一下格式,将对Post和get的处理分别封装为一个函数,完善函数注释,注释统一为/**/格式,记住,不要修改代码逻辑
最新发布
08-09
在使用 Socket 传输 JSON 数据时,可以采用以下方法来确保数据的正确传输和解析: 1. 序列化和反序列化:使用 JSON 序列化将 Python 对象转换为 JSON 字符串,然后使用 JSON 反序列化将 JSON 字符串转换回 Python 对象。 ```python import json # 将 Python 对象转换为 JSON 字符串 data = {"name": "John", "age": 30} json_data = json.dumps(data) # 将 JSON 字符串转换为 Python 对象 parsed_data = json.loads(json_data) ``` 2. 编码和解码:在发送和接收数据时,使用适当的编码和解码方法来处理字符串。 ```python # 编码字符串为字节流 encoded_data = json_data.encode('utf-8') # 解码字节流为字符串 decoded_data = encoded_data.decode('utf-8') ``` 3. 发送和接收数据:通过 Socket 进行数据的发送和接收,确保数据按照预期的格式进行传输。 ```python import socket HOST = '127.0.0.1' PORT = 1234 # 创建 Socket 对象 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 连接服务器 s.connect((HOST, PORT)) # 发送数据 s.sendall(encoded_data) # 接收数据 received_data = s.recv(1024) # 关闭连接 s.close() ``` 在发送和接收过程中,需要注意数据的分割和粘包问题,可以添加协议头和协议尾来标识数据的开始和结束,以便接收方正确解析数据。 通过以上方法,可以较好地处理 Socket 中传输 JSON 数据的格式问题,确保数据的正确传输和解析。当然,在实际情况中,还需要考虑网络异常、错误处理等问题,以保证通信的可靠性和稳定性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值