Socket编程

Socket 是对 TCP/IP
协议族的一种封装,是应用层与TCP/IP协议族通信的中间软件抽象层。从设计模式的角度看来,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。

Socket
还可以认为是一种网络间不同计算机上的进程通信的一种方法,利用三元组(ip地址,协议,端口)就可以唯一标识网络中的进程,网络中的进程通信可以利用这个标志与其它进程进行交互。

Socket 起源于 Unix ,Unix/Linux
基本哲学之一就是”一切皆文件”,都可以用”打开(open) –> 读写(write/read)
–> 关闭(close)”模式来进行操作。因此 Socket 也被处理为一种特殊的文件。

写一个简易的 WebServer

一个简易的 Server 的流程如下:

  • 1.建立连接,接受一个客户端连接。

  • 2.接受请求,从网络中读取一条 HTTP 请求报文。

  • 3.处理请求,访问资源。

  • 4.构建响应,创建带有 header 的 HTTP 响应报文。

  • 5.发送响应,传给客户端。

省略流程 3,大体的程序与调用的函数逻辑如下:

  • socket() 创建套接字

  • bind() 分配套接字地址

  • listen() 等待连接请求

  • accept() 允许连接请求

  • read()/write() 数据交换

  • close() 关闭连接

代码如下:

#include

#include

#include

#include <unistd.h>

#include <sys/socket.h>

#include <arpa/inet.h>

#include

#include

#include

using namespace std;

const int port = 9090;

const int buffer_size = 1<<20;

const int method_size = 1<<10;

const int filename_size = 1<<10;

const int common_buffer_size = 1<<10;

void handleError(const string &message);

void requestHandling(int *sock);

void sendError(int *sock);

void sendData(int *sock, char *filename);

void sendHTML(int *sock, char *filename);

void sendJPG(int *sock, char *filename);

int main()

{

int server_sock;

int client_sock;

struct sockaddr_in server_address;

struct sockaddr_in client_address;

socklen_t client_address_size;

server_sock = socket(PF_INET, SOCK_STREAM, 0);

if (server_sock == -1)

{

handleError(“socket error”);

}

memset(&server_address,0,sizeof(server_address));

server_address.sin_family = AF_INET;

server_address.sin_addr.s_addr = htonl(INADDR_ANY);

server_address.sin_port = htons(port);

if(bind(server_sock,(struct sockaddr*)&server_address,
sizeof(server_address)) == -1){

handleError(“bind error”);

}

if(listen(server_sock, 5) == -1) {

handleError(“listen error”);

}

while(true) {

client_address_size = sizeof(client_address);

client_sock = accept(server_sock, (struct sockaddr*) &client_address,
&client_address_size);

if (client_sock == -1) {

handleError(“accept error”);

}

requestHandling(&client_sock);

}

//system(“open http://127.0.0.1:9090/index.html");

close(server_sock);

return 0;

}

void requestHandling(int *sock){

int client_sock = *sock;

char buffer[buffer_size];

char method[method_size];

char filename[filename_size];

read(client_sock, buffer, sizeof(buffer)-1);

if(!strstr(buffer, “HTTP/“)) {

sendError(sock);

close(client_sock);

return;

}

strcpy(method, strtok(buffer,” /“));

strcpy(filename, strtok(NULL, “ /“));

if(0 != strcmp(method, “GET”)) {

sendError(sock);

close(client_sock);

return;

}

sendData(sock, filename);

}

void sendData(int *sock, char *filename) {

int client_sock = *sock;

char buffer[common_buffer_size];

char type[common_buffer_size];

strcpy(buffer, filename);

strtok(buffer, “.”);

strcpy(type, strtok(NULL, “.”));

if(0 == strcmp(type, “html”)){

sendHTML(sock, filename);

}else if(0 == strcmp(type, “jpg”)){

sendJPG(sock, filename);

}else{

sendError(sock);

close(client_sock);

return ;

}

}

void sendHTML(int *sock, char *filename) {

int client_sock = *sock;

char buffer[buffer_size];

FILE *fp;

char status[] = “HTTP/1.0 200 OKrn”;

char header[] = “Server: A Simple Web ServerrnContent-Type:
text/htmlrnrn”;

write(client_sock, status, strlen(status));

write(client_sock, header, strlen(header));

fp = fopen(filename, “r”);

if(!fp){

sendError(sock);

close(client_sock);

handleError(“failed to open file”);

return ;

}

fgets(buffer,sizeof(buffer), fp);

while(!feof(fp)) {

write(client_sock, buffer, strlen(buffer));

fgets(buffer, sizeof(buffer), fp);

}

fclose(fp);

close(client_sock);

}

void sendJPG(int *sock, char *filename) {

int client_sock = *sock;

char buffer[buffer_size];

FILE *fp;

FILE *fw;

char status[] = “HTTP/1.0 200 OKrn”;

char header[] = “Server: A Simple Web ServerrnContent-Type:
image/jpegrnrn”;

write(client_sock, status, strlen(status));

write(client_sock, header, strlen(header));

fp = fopen(filename, “rb”);

if(NULL == fp){

sendError(sock);

close(client_sock);

handleError(“failed to open file”);

return ;

}

fw = fdopen(client_sock, “w”);

fread(buffer, 1, sizeof(buffer), fp);

while (!feof(fp)){

fwrite(buffer, 1, sizeof(buffer), fw);

fread(buffer, 1, sizeof(buffer), fp);

}

fclose(fw);

fclose(fp);

close(client_sock);

}

void handleError(const string &message) {

cout<<message;

exit(1);

}

void sendError(int *sock){

int client_sock = *sock;

char status[] = “HTTP/1.0 400 Bad Requestrn”;

char header[] = “Server: A Simple Web ServerrnContent-Type:
text/htmlrnrn”;

char body[] = “Bad<br>Request

400 Bad
Request

“;

write(client_sock, status, sizeof(status));

write(client_sock, header, sizeof(header));

write(client_sock, body, sizeof(body));

}


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!