概念一:Socket: a way to speak to other programs using standard Linux file descriptors.
概念二:Data Encapsulation:
1> a packet is born, the packet is wrapped ("encapsulated") in a header (and rarely a footer) by the first protocol (say, the TFTP protocol), then the whole thing (TFTP header included) is encapsulated again by the next protocol (say, UDP), then again by the next (IP), then again by the final protocol on the hardware (physical) layer (say, Ethernet).
2> When another computer receives the packet, the hardware strips the Ethernet header, the kernel strips the IP and UDP headers, the TFTP program strips the TFTP header, and it finally has the data.
Notes: you can write sockets programs that are exactly the same without caring how the data is physically transmitted (serial, thin Ethernet, AUI, whatever)
because programs on lower levels deal with it for you. The actual network hardware and topology is transparent to the socket programmer.
3> All you have to do for stream sockets is send() the data out. All you have to do for datagram sockets is encapsulate the packet in the method of your choosing and sendto() it out. The kernel builds the Transport Layer and Internet Layer on for you and the hardware does the Network Access Layer. Ah, modern technology.
概念三:字节序
1>there are two byte orderings: most significant byte (sometimes called an "octet") first, or least significant byte first. The former is called "Network Byte Order".(htons(), htonl()...)
概念四:常用结构体
struct sockaddr {
unsigned short sa_family; //address family, AF_xxx
char sa_data[14]; //14 bytes of protocol address
};
struct sockaddr_in {
short int sin_family; //Address family
unsigned short int sin_port; //Port number
struct in_addr sin_addr; //Internet address
unsigned char sin_zero[8];//Same size as struct sockaddr
};
struct in_addr {
unsigned long s_addr; //load with inet_addr()
};
操作集(真的弄懂了吗?):
#系列一:结构体赋值
struct sockaddr_in my_addr;
//memset(&(my_addr.sin_zero), ’\0’, 8);
bzero(&my_addr, sizeof(my_addr)); //memset(&my_addr, 0, sizeof(my_addr));
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(PORTNUM);
my_addr.sin_addr.s_addr = htonl(INADDR_ANY); //inet_addr("127.0.0.1");
#系列二: socket API调用
1. socket(AF_INET, SOCK_STREAM, 0); //listensd
2. bind(serversd, (struct sockaddr *) &my_addr, sizeof(my_addr));
3. listen(serversd, BACKLOG);
4. accept(serversd, (SA *) &their_addr, (socklen_t *) &size); //connectsd
5. close(sockfd);
#系列三: I/O调用
// writes up to count bytes from the buffer pointed buf to the file
// referred to by the file descriptor fd.
1. ssize_t write(int fd, const void *buf, size_t count);
// attempts to read up to count bytes from file descriptor fd into
// the buffer starting at buf.
2. ssize_t read (int fd, void *buf, size_t count);
3. ssize_t send (int sockfd, const void *msg, int len, int flags);
4. ssize_t recv (int sockfd, const void *msg, int len, int flags);
P.S.
1. endian.c //测试机器是big endian || little endian 加深对概念理解
2. server.c //面向连接C/S模式server端demo程序(多了个pthread下次blog再交流)
3. client.c(user-defined)//可以用"telnet"测试哈,具体使用方法manpage加互联网ok了.(最好用下netstat观察状态神马的)
3. 基础东西理解差不多了,组装起来也就形成所谓的"算法"了,重思想加实践.
4. 基础没你想象地那么容易,肯定也没那么难; 勤动脑,多动手, 基础基础。(利用好手头的工具:gcc|man|google|wikipedia stackoverflow|csdn etc.)
5. 过早关注细节,就容易陷进去了,就像"过早优化"一样, 正确的时间做正确的事情.
6. 欢迎大家批评指教
7. ...
概念二:Data Encapsulation:
1> a packet is born, the packet is wrapped ("encapsulated") in a header (and rarely a footer) by the first protocol (say, the TFTP protocol), then the whole thing (TFTP header included) is encapsulated again by the next protocol (say, UDP), then again by the next (IP), then again by the final protocol on the hardware (physical) layer (say, Ethernet).
2> When another computer receives the packet, the hardware strips the Ethernet header, the kernel strips the IP and UDP headers, the TFTP program strips the TFTP header, and it finally has the data.
Notes: you can write sockets programs that are exactly the same without caring how the data is physically transmitted (serial, thin Ethernet, AUI, whatever)
because programs on lower levels deal with it for you. The actual network hardware and topology is transparent to the socket programmer.
3> All you have to do for stream sockets is send() the data out. All you have to do for datagram sockets is encapsulate the packet in the method of your choosing and sendto() it out. The kernel builds the Transport Layer and Internet Layer on for you and the hardware does the Network Access Layer. Ah, modern technology.
概念三:字节序
1>there are two byte orderings: most significant byte (sometimes called an "octet") first, or least significant byte first. The former is called "Network Byte Order".(htons(), htonl()...)
概念四:常用结构体
struct sockaddr {
unsigned short sa_family; //address family, AF_xxx
char sa_data[14]; //14 bytes of protocol address
};
struct sockaddr_in {
short int sin_family; //Address family
unsigned short int sin_port; //Port number
struct in_addr sin_addr; //Internet address
unsigned char sin_zero[8];//Same size as struct sockaddr
};
struct in_addr {
unsigned long s_addr; //load with inet_addr()
};
操作集(真的弄懂了吗?):
#系列一:结构体赋值
struct sockaddr_in my_addr;
//memset(&(my_addr.sin_zero), ’\0’, 8);
bzero(&my_addr, sizeof(my_addr)); //memset(&my_addr, 0, sizeof(my_addr));
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(PORTNUM);
my_addr.sin_addr.s_addr = htonl(INADDR_ANY); //inet_addr("127.0.0.1");
#系列二: socket API调用
1. socket(AF_INET, SOCK_STREAM, 0); //listensd
2. bind(serversd, (struct sockaddr *) &my_addr, sizeof(my_addr));
3. listen(serversd, BACKLOG);
4. accept(serversd, (SA *) &their_addr, (socklen_t *) &size); //connectsd
5. close(sockfd);
#系列三: I/O调用
// writes up to count bytes from the buffer pointed buf to the file
// referred to by the file descriptor fd.
1. ssize_t write(int fd, const void *buf, size_t count);
// attempts to read up to count bytes from file descriptor fd into
// the buffer starting at buf.
2. ssize_t read (int fd, void *buf, size_t count);
3. ssize_t send (int sockfd, const void *msg, int len, int flags);
4. ssize_t recv (int sockfd, const void *msg, int len, int flags);
P.S.
1. endian.c //测试机器是big endian || little endian 加深对概念理解
2. server.c //面向连接C/S模式server端demo程序(多了个pthread下次blog再交流)
3. client.c(user-defined)//可以用"telnet"测试哈,具体使用方法manpage加互联网ok了.(最好用下netstat观察状态神马的)
3. 基础东西理解差不多了,组装起来也就形成所谓的"算法"了,重思想加实践.
4. 基础没你想象地那么容易,肯定也没那么难; 勤动脑,多动手, 基础基础。(利用好手头的工具:gcc|man|google|wikipedia stackoverflow|csdn etc.)
5. 过早关注细节,就容易陷进去了,就像"过早优化"一样, 正确的时间做正确的事情.
6. 欢迎大家批评指教
7. ...
/*
*pthreadServer.c
*gcc -o serverDemo pthreadServer.c -lpthread
*Data: Friday 28 June 2013
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <pthread.h>
#define BACKLOG 5
#define BUFFERSIZE 2000
#define PORTNUM 8888
#define SA struct sockaddr
void Die(char *mess) { perror(mess); exit(1); } //error handler
void *connection_handler(void *); //start function (pthread_create())
int
main(int argc, char *argv[])
{
int serversd, connectsd, size;
struct sockaddr_in my_addr, their_addr;
pthread_t sniffer_thread;
char *message;
//Create a socket for server
if ((serversd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
Die("Failed to create socket");
}
//Prepare the sockaddr_in structure
bzero(&my_addr, sizeof(my_addr)); // Clear structure
my_addr.sin_family = AF_INET;
my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
my_addr.sin_port = htons(PORTNUM);
//Bind the server socket
if (bind(serversd, (SA *) &my_addr, sizeof(my_addr)) < 0) {
Die("Failed to bind the server socket");
}
puts("bind done");
//Listen on the server socket
if (listen(serversd, BACKLOG) < 0) {
Die("Failed to listen on the server");
}
//Accept the incoming connections
puts("Waiting for incoming connection...");
size = sizeof(struct sockaddr_in);
while (1) { //main accept() loop
if ((connectsd = accept(serversd, (SA *) &their_addr, (socklen_t *) &size)) == -1) {
perror("accept");
continue;
}
printf("server: got connection from %s\n", inet_ntoa(their_addr.sin_addr));
if (pthread_create(&sniffer_thread, NULL, connection_handler, (void *) &connectsd) < 0) {
Die("Could not create thread");
}
//puts("Handler assigned");
//Now join the thread, so that we don't terminate before the thread
//pthread_join(sniffer_thread, NULL);
}
close(serversd);
exit(0);
}
//This will handle connection for each client
void *connection_handler(void *arg) {
//Get the socket descriptor
puts("Handler assigned");
int sock = *(int *)arg;
int read_size;
char *message, buffer[BUFFERSIZE];
//Send message to the client
message = "I am your connection handler, now I shall repeat what you type\n";
write(sock, message, strlen(message));
//Receive response from client
if ((read_size = recv(sock, buffer, BUFFERSIZE, 0)) < 0) {
Die("Failed to receive initial bytes from client");
}
while (read_size > 0) {
if (send(sock, buffer, read_size, 0) != read_size) {
Die("Failed to send bytes to client");
}
if ((read_size = recv(sock, buffer, BUFFERSIZE, 0)) < 0) {
Die("Failed to receive additional bytes from client");
}
}
close(sock);
return;
}
//endian.c
#include <stdio.h>
int
main(void)
{
int i; //Loop variable
long x= 0x12345A80; //Value to play with
unsigned char* ptr = (char*) &x; //Byte pointer
//Oberser value in host byte order
printf("In the host byte order:\n");
printf("x in hex: %x\n", x);
printf("x by bytes: ");
for (i = 0; i < sizeof(long); i++) {
printf("%x\t", ptr[i]);
}
printf("\n");
//Oberser value in network byte order
x = htonl(x);
printf("\nAfter htonl()\n");
printf("x in hex: %x\n", x);
printf("x by bytes: ");
for (i = 0; i < sizeof(long); i++) {
printf("%x\t", ptr[i]);
}
printf("\n");
}