linux套接字编程笔记(二)–简单的TCP套接字应用程序
这里参照linux套接字编程笔记(一)–TCP与UDP提到的流程,编写了一个简易的C语言TCP server和client,主要是留着代码供自己后面参考,否则每次再用C或者C++写还得搜别人的代码,可能还有坑。。。
linux套接字编程笔记(一)–TCP与UDP,链接是http://blog.csdn.net/qq_15437667/article/details/70194698
代码如下
client
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <signal.h>
#define IP_SIZE (20)
#define SERVER_LISTEN_PORT (10000)
#define BUFFER_SIZE (4096)
#define MAX_FILE_NAME_LEN (256)
void tcpClientUploadFile(int sockFd, struct sockaddr_in *serverAddr, char *filePath);
int main(int argc, char *argv[]) {
int sockFd = 0;
char serverIP[IP_SIZE];
struct sockaddr_in serverAddr;
if (argc == 2) {
strcpy(serverIP, argv[1]);
} else if (argc == 1){
strcpy(serverIP, "127.0.0.1");
} else {
printf("error command\n");
exit(-1);
}
//create socket
sockFd = socket(AF_INET, SOCK_STREAM, 0);
if (sockFd < 0) {
printf("create socket failed\n");
exit(-1);
}
/* set serverAddr */
/*
struct sockaddr
{
unsigned short sa_family;
char sa_data[14];
};
struct sockaddr_in {
short sin_family; // 2 bytes e.g. AF_INET, AF_INET6
unsigned short sin_port; // 2 bytes e.g. htons(3490)
struct in_addr sin_addr; // 4 bytes see struct in_addr, below
char sin_zero[8]; // 8 bytes zero this if you want to
};
struct in_addr {
unsigned long s_addr; // 4 bytes load with inet_pton()
};
*/
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(SERVER_LISTEN_PORT);
serverAddr.sin_addr.s_addr = inet_addr(serverIP);
//connect the server
if (connect(sockFd, (struct sockaddr *)&serverAddr, sizeof(struct sockaddr)) < 0) {
printf("connect failed\n");
exit(-1);
}
printf("connect server success\n");
//push file
tcpClientUploadFile(sockFd, &serverAddr, "./test.go");
close(sockFd);
return 0;
}
void tcpClientUploadFile(int sockFd, struct sockaddr_in *serverAddr, char *filePath) {
FILE *stream;
char buffer[BUFFER_SIZE];
char filename[MAX_FILE_NAME_LEN];
int count = 0;
bzero(buffer, BUFFER_SIZE);
strcpy(filename, strrchr(filePath, '/') + 1);
printf("filename is %s\n", filename);
strncpy(buffer, filename, strlen(filename) > MAX_FILE_NAME_LEN ? MAX_FILE_NAME_LEN : strlen(filename));
//send filename
send(sockFd, buffer, BUFFER_SIZE, 0);
stream = fopen(filePath, "r");
if (NULL == stream) {
printf("open file %s failed\n", filePath);
exit(-1);
}
while((count = fread(buffer, 1, BUFFER_SIZE, stream)) > 0) {
//printf
if (send(sockFd, buffer, count, 0) < 0) {
printf("send failed\n");
break;
}
bzero(buffer, BUFFER_SIZE);
}
printf("upload success\n");
fclose(stream);
}
server
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <signal.h>
#define IP_SIZE (20)
#define SERVER_LISTEN_PORT (10000)
#define BUFFER_SIZE (4096)
#define MAX_FILE_NAME_LEN (256)
void tcpServerDownloadFile (int connFd, struct sockaddr_in *clientAddr, char *fileServerRoot);
int main(int argc, char *argv[]) {
/*char serverIP[IP_SIZE];
if (argc >= 2) {
}*/
char serverIP[IP_SIZE] = "127.0.0.1";
int sockFd = 0;
struct sockaddr_in serverAddr;
bzero(&serverAddr, sizeof(serverAddr));
/* create sock */
sockFd = socket(AF_INET, SOCK_STREAM, 0);
if (sockFd < 0) {
perror("sock init failed!\n");
exit(-1);
} else {
printf("create socket success!\n");
}
/* set serverAddr */
/*
struct sockaddr
{
unsigned short sa_family;
char sa_data[14];
};
struct sockaddr_in {
short sin_family; // 2 bytes e.g. AF_INET, AF_INET6
unsigned short sin_port; // 2 bytes e.g. htons(3490)
struct in_addr sin_addr; // 4 bytes see struct in_addr, below
char sin_zero[8]; // 8 bytes zero this if you want to
};
struct in_addr {
unsigned long s_addr; // 4 bytes load with inet_pton()
};
*/
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(SERVER_LISTEN_PORT);
serverAddr.sin_addr.s_addr = inet_addr(serverIP);
//bind
if (bind(sockFd, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) > 0) {
perror("bind error\n");
exit(-1);
} else {
printf("server bind success!\n");
}
//listen
if(listen(sockFd, 5)) {
printf("server listen failed, err is %d\n", errno);
exit(-1);
} else {
printf("listen success\n");
}
struct sockaddr_in clientAddr;
socklen_t length = sizeof(clientAddr);
int connFd = 0;
while (1) {
//accept
connFd = accept(sockFd, (struct sockaddr *)&clientAddr, &length);
if (connFd == -1) {
printf("accpet err\n");
continue;
}
printf("get connection\n");
//pull file
tcpServerDownloadFile(connFd, &clientAddr, "./");
close(connFd);
}
return 0;
}
void tcpServerDownloadFile (int connFd, struct sockaddr_in *clientAddr, char *fileServerRoot) {
char buffer[BUFFER_SIZE];
char filename[MAX_FILE_NAME_LEN];
char fileServerPath[MAX_FILE_NAME_LEN];
FILE *stream = NULL;
int count = 0;
int dataLen = 0;
int writeLen = 0;
bzero(buffer, BUFFER_SIZE);
count = recv(connFd, buffer, BUFFER_SIZE, 0);
if (count < 0) {
printf("recv filename failed!\n");
exit(1);
}
strncpy(filename, buffer, strlen(buffer) > MAX_FILE_NAME_LEN? MAX_FILE_NAME_LEN : strlen(buffer));
strcpy(fileServerPath, fileServerRoot);
strcpy(fileServerPath, filename);
printf("file path:\n %s\n", fileServerPath);
//open a file
stream = fopen(fileServerPath, "w");
if (NULL == stream) {
printf("create file failed\n");
exit(-1);
}
bzero(buffer, BUFFER_SIZE);
printf("start recv file\n");
while((dataLen = recv(connFd, buffer, BUFFER_SIZE, 0)) > 0) {
//if (dataLen)
writeLen = fwrite(buffer, sizeof(char), dataLen, stream);
if (writeLen != dataLen) {
printf("write error, upload interupt\n");
exit(-1);
}
bzero(buffer, BUFFER_SIZE);
}
printf("upload file ok\n");
fclose(stream);
}
后面扩展成多进程、多线程、通过select、epoll编程、libevent(实际上是封装了linux下的epoll和win下相应接口)都会基于该代码进行微调修改
代码在github路径下
https://github.com/Miss-you/network-program-test.git