最近开始学习linux网络通信, 学了一周了,有了一些基本的理解.下面是一个小实例.
程序很简单,服务端与客户端进行简单的通信.采用自定义通信协议,协议的格式很简单:
第一个字段是类型,如'a',表示创建新文件等
代码很简单:
server端
/*
* Myserver2.cpp
*
* Created on: 2015-1-9
* Author: shuyan
*/
#include "Myserver2.h"
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include <unistd.h>
#include <iostream>
#include <pthread.h>
#define DEFAULT_PORT 8007
#define MAXLINE 4096
using namespace std;
void create_file(char * fileName, char* filePath, char * data);
void * create_file_2(void * data);
struct mydata {
char type;
int leng;
char data[20];
//char *data;
char fileName[20];
char filePath[50];
};
int main() {
int sock_fd, connect_fd;
struct sockaddr_in servaddr;
char * buff = new char[4096];
int n;
mydata *recvData = (mydata *) malloc(sizeof(mydata));
memset(recvData, 0, sizeof(mydata));
memset(buff, 0, 4096);
//1.
if ((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("create socket error: %s(errno: %d)\n", strerror(errno), errno);
exit(0);
}
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_addr.s_addr = htonl(INADDR_ANY );
servaddr.sin_port = htons(DEFAULT_PORT);
servaddr.sin_family = AF_INET;
//2.
if (bind(sock_fd, (struct sockaddr *) &servaddr, sizeof(servaddr)) == -1) {
printf("bind socket error: %s(errno: %d)\n", strerror(errno), errno);
exit(0);
};
//3.
if (listen(sock_fd, 10) == -1) {
printf("listen socket error: %s(errno: %d)\n", strerror(errno), errno);
exit(0);
}
printf("======waiting for client's request======\n");
while (1) {
//4.
if ((connect_fd = accept(sock_fd, (struct sockaddr*) NULL, NULL)) < 0) {
printf("accept socket error: %s(errno: %d)", strerror(errno),
errno);
continue;
}
//n = recv(connect_fd, buff, MAXLINE, 0);
if ((n = recv(connect_fd, buff, MAXLINE, 0)) > 0) {
cout << "rec Size " << n << endl;
cout << "sizeof(mydata)" << sizeof(mydata);
if (n >= 100) {
recvData = (mydata *) buff;
switch (recvData->type) {
case 'a':
//使用传来的数据创建新文件
cout << "hahha" << endl;
pthread_t pid;
pthread_create(&pid, NULL, create_file_2,
(void *) recvData);
//pthread_join(pid,NULL);
/*
* 多进程
* pid_t fpid;
fpid = fork();
if (fpid == 0) {
printf("i am the child process, my process id is %d/n",getpid());
create_file(recvData->fileName, recvData->filePath,
recvData->data);
}else {
printf("i am the parent process, my process id is %d/n",getpid());
}*/
break;
case 'b':
//追加文件
break;
case 'c':
//删除文件
break;
default:
perror("error");
break;
}
}
}
cout << "=====================" << endl;
if (n == -1) {
perror("receive error");
}
//向客户端发送回应数据
if (send(connect_fd, "I received it", 16, 0) == -1) {
perror("send error");
}
buff[n] = '\0';
printf("recv msg from client\n");
close(connect_fd);
}
close(sock_fd);
}
void create_file(char * fileName, char* filePath, char * data) {
cout << "name:" << fileName << ",path:" << filePath << ",data:" << data
<< endl;
char * newName = strcat(filePath, fileName);
FILE * fp;
fp = fopen(newName, "w+");
if (fp != NULL) {
fwrite(data, sizeof(char), sizeof(data), fp);
fclose(fp);
}
}
void * create_file_2(void * data) {
mydata *data_m = (struct mydata *) data;
cout << "name:" << data_m->fileName << ",path:" << data_m->filePath
<< ",data:" << data_m->data << endl;
char * newName = strcat(data_m->filePath, data_m->fileName);
FILE * fp;
fp = fopen(newName, "a+");
if (fp != NULL) {
fwrite(data_m->data, sizeof(char), strlen(data_m->data), fp);
fclose(fp);
}
return 0;
}
客户端client
/*
* Myclient2.cpp
*
* Created on: 2015-1-9
* Author: shuyan
*/
#include "Myclient2.h"
#include <sys/types.h>
#include <sys/socket.h>
#include<errno.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <iostream>
#define MAXLINE 4096
#define DEFAULT_PORT 8007
using namespace std;
int main() {
char recvline[4096], sendline[4096];
char buf[MAXLINE];
int socket_fd;
int receive_len;
struct sockaddr_in servaddr;
int send_num;
struct mydata {
char type;
int leng;
char data[20];
char fileName[20];
char filePath[50];
};
mydata data1 = { 'a', 10, "abcdefghij", "test.txt", "/home/shuyan/java/" };
//初始化socket
if ((socket_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
printf("create socket error:%s(errno:%d)\n", strerror(errno), errno);
exit(0);
}
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_port = htons(DEFAULT_PORT);
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
//链接
if (connect(socket_fd, (struct sockaddr*) &servaddr, sizeof(servaddr))
< 0) {
printf("connect error: %s(errno: %d)\n", strerror(errno), errno);
exit(0);
}
printf("send msg to server: \n");
/*
*consle input your message
*/
/**
*
fgets(sendline, 1000, stdin);
if (send(socket_fd, sendline, sizeof(sendline), 0) < 0) {
printf("send msg error: %s(errno: %d)\n", strerror(errno), errno);
exit(0);
}
*/
if ((send_num = send(socket_fd, &data1, sizeof(data1), 0)) < 0) {
printf("send msg error: %s(errno: %d)\n", strerror(errno), errno);
exit(0);
}
cout << "send_num" << send_num << endl;
if ((receive_len = recv(socket_fd, buf, MAXLINE, 0)) == -1) {
perror("recv error");
exit(1);
}
buf[receive_len] = '\0';
printf("Received : %s ", buf);
close(socket_fd);
exit(0);
}
需要注意的地方:
1.当通信传输的数据不是简单的文本而是结构体之类的复杂数据,两边都需要使用结构体对数据进行封包\解包.
2.创建多线程时,如果需要传递的参数有多个.也需要将其封装成结构体,然后在强制转换后进行传递.