Linux socket 及多线程 实例

本文介绍了一个简单的Linux自定义网络通信示例,服务端与客户端通过自定义协议进行交互,实现文件创建等功能。文章提供了完整的源代码,并强调了数据封包与多线程参数传递的重要性。

最近开始学习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.创建多线程时,如果需要传递的参数有多个.也需要将其封装成结构体,然后在强制转换后进行传递.


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值