使用Socket发送非字符串数据
在之前的文章中,实现了一个从客户端发送字符串数据到服务器的Socket程序。但是在实际应用中,往往需要通过Socket传输其他复杂一点的数据,例如struct结构或者uint8_t数组等等。
之前我尝试了直接将uint8_t数组从socket发送,但是服务端只是收到了0x00数据。后来在网上找了一些资料,终于找到了这篇文章:Linux C Socket编程发送结构体、文件详解及实例 , 按照这篇文章使用memcpy()函数将要发送的数据放入char*数组指针中。只是都是Linux的代码,我这里稍稍修改下,客户端使用Windows,服务端使用Linux。
Windows客户端代码
#include <stdio.h>
#include <winsock2.h>
#include <string.h>
#include <stdlib.h>
#define PORT 3389 //服务端端口
#define BUFFER_SIZE 1024 //缓存
#define SA struct sockaddr
#define bzero(b,len) (memset((b), '\0', (len)), (void) 0)
#define bcopy(b1,b2,len) (memmove((b2), (b1), (len)), (void) 0)
#pragma comment(lib,"ws2_32.lib") //Winsock Library
#pragma warning(disable:4996)
// 定义要发送的结构体
typedef struct
{
int ab;
int num[100];
}Node;
int main(void)
{
WSADATA wsa;
SOCKET sockfd;
struct sockaddr_in servaddr;
printf("\nInitialising Winsock...");
if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
{
printf("Failed. Error Code : %d", WSAGetLastError());
return 1;
}
printf("Initialised.\n");
// socket create and varification
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1) {
printf("socket creation failed...\n");
exit(0);
}
else
printf("Socket successfully created..\n");
bzero(&servaddr, sizeof(servaddr));
// assign IP, PORT
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = inet_addr("158.101.15.187");
servaddr.sin_port = htons(PORT);
// connect the client socket to server socket
if (connect(sockfd, (SA*)&servaddr, sizeof(servaddr)) != 0) {
printf("connection with the server failed...\n");
exit(0);
}
else
printf("connected to the server..\n");
// send data
Node* myNode = (Node*)malloc(sizeof(Node));
myNode->ab = 123;
myNode->num[0] = 110;
myNode->num[99] = 99;
int needSend = sizeof(Node);
char* buffer = (char*)malloc(needSend);
memcpy(buffer, myNode, needSend);
int pos = 0;
int len = 0;
while (pos < needSend)
{
len = send(sockfd, buffer + pos, BUFFER_SIZE, 0);
if (len <= 0)
{
printf("ERROR");
break;
}
pos += len;
}
free(buffer);
free(myNode);
// close the socket
closesocket(sockfd);
WSACleanup();
return 0;
}Linux服务端
#include <stdio.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#define PORT 3389
#define BUFFER_SIZE 1024
#define SA struct sockaddr
static void sig_handler(int sig)
{
int retval;
if ( sig == SIGCHLD )
{
// 等待子程序的結束狀態
wait(&retval);
printf("CATCH SIGNAL PID=%d\n",getpid());
}
}
// 定义的结构体一定要个客户端的相同,顺序不能更改,否则接受的数据解析不正确
typedef struct
{
int ab;
int num[100];
}Node;
// Driver function
int main(void)
{
int sockfd, connfd;
struct sockaddr_in servaddr, cli;
socklen_t len;
pid_t pid;
// socket create and verification
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1) {
printf("socket creation failed...\n");
exit(0);
}
else
printf("Socket successfully created..\n");
bzero(&servaddr, sizeof(servaddr));
// assign IP, PORT
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(PORT);
int reuse = 1;
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(int)) == -1)
printf("Can't set the reuse option on the socket");
// Binding newly created socket to given IP and verification
if ((bind(sockfd, (SA*)&servaddr, sizeof(servaddr))) != 0) {
printf("socket bind failed...\n");
exit(0);
}
else
printf("Socket successfully binded..\n");
// Now server is ready to listen and verification
if ((listen(sockfd, 5)) != 0) {
printf("Listen failed...\n");
exit(0);
}
else
printf("Server listening..\n");
while(1)
{
// Accept the data packet from client and verification
len = sizeof(cli);
connfd = accept(sockfd, (SA*)&cli, &len);
if (connfd < 0) {
printf("server acccept failed...\n");
exit(0);
}
else
printf("server acccept the client...\n");
// 呼叫 signal 來接收 SIGCHLD 信號
signal(SIGCHLD,sig_handler);
pid = fork();
if(pid < 0)
printf("ERROR on fork");
if(pid == 0)
{
close(sockfd);
//recv data
Node *myNode=(Node*)malloc(sizeof(Node));
int needRecv=sizeof(Node);
char *buffer=(char*)malloc(needRecv);
int pos=0;
int len;
while(pos < needRecv)
{
len = recv(connfd, buffer+pos, BUFFER_SIZE, 0);
if (len < 0)
{
printf("Server Recieve Data Failed!\n");
break;
}
pos+=len;
}
memcpy(myNode,buffer,needRecv);
printf("recv over ab=%d num[0]=%d num[99]=%d\n",myNode->ab,myNode->num[0],myNode->num[99]);
free(buffer);
free(myNode);
close(connfd);
exit(0);
}
else
{
close(connfd);
}
}
// After chatting close the socket
close(sockfd);
return 0;
}如果是要发送uint8_t
Windows客户端
#include <stdio.h>
#include <winsock2.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#define PORT 3389
#define BUFFER_SIZE 1024
#define SA struct sockaddr
#define bzero(b,len) (memset((b), '\0', (len)), (void) 0)
#define bcopy(b1,b2,len) (memmove((b2), (b1), (len)), (void) 0)
#pragma comment(lib,"ws2_32.lib") //Winsock Library
#pragma warning(disable:4996)
typedef struct
{
int ab;
int num[100];
}Node;
int main(void)
{
WSADATA wsa;
SOCKET sockfd;
struct sockaddr_in servaddr;
printf("\nInitialising Winsock...");
if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
{
printf("Failed. Error Code : %d", WSAGetLastError());
return 1;
}
printf("Initialised.\n");
// socket create and varification
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1) {
printf("socket creation failed...\n");
exit(0);
}
else
printf("Socket successfully created..\n");
bzero(&servaddr, sizeof(servaddr));
// assign IP, PORT
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = inet_addr("158.101.15.187");
servaddr.sin_port = htons(PORT);
// connect the client socket to server socket
if (connect(sockfd, (SA*)&servaddr, sizeof(servaddr)) != 0) {
printf("connection with the server failed...\n");
exit(0);
}
else
printf("connected to the server..\n");
// send data
uint8_t input_data[] = { 0x01,0x03,0x04,0x01,0xB5,0x00,0xB9,0x2B,0x9B };
int needSend = sizeof(input_data);
char* buffer = (char*)malloc(needSend);
memcpy(buffer, input_data, needSend);
int pos = 0;
int len = 0;
while (pos<needSend)
{
len = send(sockfd, buffer + pos, BUFFER_SIZE, 0);
if (len <= 0)
{
printf("ERROR");
break;
}
pos += len;
}
free(buffer);
// close the socket
closesocket(sockfd);
WSACleanup();
return 0;
}Linux服务端
#include <stdio.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdint.h>
#define PORT 3389
#define BUFFER_SIZE 1024
#define SA struct sockaddr
static void sig_handler(int sig)
{
int retval;
if ( sig == SIGCHLD )
{
// 等待子程序的結束狀態
wait(&retval);
printf("CATCH SIGNAL PID=%d\n",getpid());
}
}
// Driver function
int main(void)
{
int sockfd, connfd;
struct sockaddr_in servaddr, cli;
socklen_t len;
pid_t pid;
// socket create and verification
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1) {
printf("socket creation failed...\n");
exit(0);
}
else
printf("Socket successfully created..\n");
bzero(&servaddr, sizeof(servaddr));
// assign IP, PORT
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(PORT);
int reuse = 1;
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(int)) == -1)
printf("Can't set the reuse option on the socket");
// Binding newly created socket to given IP and verification
if ((bind(sockfd, (SA*)&servaddr, sizeof(servaddr))) != 0) {
printf("socket bind failed...\n");
exit(0);
}
else
printf("Socket successfully binded..\n");
// Now server is ready to listen and verification
if ((listen(sockfd, 5)) != 0) {
printf("Listen failed...\n");
exit(0);
}
else
printf("Server listening..\n");
while(1)
{
// Accept the data packet from client and verification
len = sizeof(cli);
connfd = accept(sockfd, (SA*)&cli, &len);
if (connfd < 0) {
printf("server acccept failed...\n");
exit(0);
}
else
printf("server acccept the client...\n");
// 呼叫 signal 來接收 SIGCHLD 信號
signal(SIGCHLD,sig_handler);
pid = fork();
if(pid < 0)
printf("ERROR on fork");
if(pid == 0)
{
close(sockfd);
//recv data
uint8_t input_data[9];
int needRecv = sizeof(input_data);
char *buffer = (char*)malloc(needRecv);
int pos = 0;
int len = 0;
while(pos < needRecv)
{
len = recv(connfd, buffer+pos, BUFFER_SIZE, 0);
if(len < 0)
{
printf("Server Recieve Data Failed!\n");
break;
}
pos+=len;
}
memcpy(input_data,buffer,needRecv);
for(int i = 0; i < needRecv; i++)
{
printf("0x%02x, ", input_data[i]);
}
printf("\n");
free(buffer);
close(connfd);
exit(0);
}
else
{
close(connfd);
}
}
// After chatting close the socket
close(sockfd);
return 0;
}以上代码均经过测试,可以正常运行,Windows下使用 Visual Studio 2019,Linux是Debian 10.10 gcc (Debian 8.3.0-6) 8.3.0
评论已关闭