Ch13 TCP/IP和网络编程
13.2 TCP/IP
TCP/IP数据流路径
13.3 IP主机和IP地址
-
主机是支持TCP/IP协议的计算机或设备。
-
IP地址分为两部分,即NetworkID字段和HostID字段。
13.4 IP协议
- IP协议用于在IP主机之间发送/接收数据包,IP协议尽最大努力交付数据包。
13.5 IP数据包格式
IP数据包由IP头、发送方IP地址和接收方IP地址以及数据组成。每个IP数据包的大小最大为64KB。
13.12 网络编程
13.12.2 服务器-客户机计算模型
大多数网络编程任务都基于服务器-客户机计算模型。在服务器-客户机计算模财中我们首先在服务器主机上运行服务器进程。然后,我们从客户机主机运行客户机在UDP中,服务器等待来自客户机的数据报,处理数据报并生成对客户机的响应。在TCP中,服务器等待客户机连接。客户机首先连接到服务器,在客户机和服务器之间建立一个虚拟电路,建立连接后,服务器和客户机可以交换连续的数据流。
13.13 套接字编程
在网络编程中,TCP/IP的用户界面是通过一系列C语言库函数和系统调用来实现的, 这些函数和系统调用统称为套接字API (( Rago 1993; Stevens等2004 )。
13.13.1 套接字地址
struct sockaddr_in {
sa_family_t sin_family; // AF_INET for TCP/IP
in_port_t sin_port; // port number
struct in_addr sin_addr; // IP address
};
struct in_addr { // internet address
uint32_t s_addr; // IP address in network byte order
};
- TCP/IP 网络的 sin_family 始终设置为 AF_INET。
- sm_port包含按网络字节顺序排列的端口号。
- sin_addr是按网络字节顺序排列的主机IP地址。
13.13.2 套接字API
-
init套接字
//udp int udp_sock = socket(AF_INET, SOCK_DGRAM, 0); //tcp int tcp_sock = socket(AF_INET, SOCK_STRAM, 0);
-
int bind(int sockfd, struct sockaddr *addr, socklen_t addrlen)
-
UDP套接字
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen); ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);
-
TCP套接字
int listen(int sockfd, int backlog); int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
-
send()/read() and recv/write()
ssize_t send(int sockfd, const void *buf, size_t len, int flags); ssize_t write(sockfd, void *buf, size_t, len) ssize_t recv(int sockfd, void *buf, size_t len, int flags); ssize_t read(sockfd, void *buf, size_t len);
------------恢复内容开始------------
# Ch13 TCP/IP和网络编程13.2 TCP/IP
TCP/IP数据流路径
13.3 IP主机和IP地址
-
主机是支持TCP/IP协议的计算机或设备。
-
IP地址分为两部分,即NetworkID字段和HostID字段。
13.4 IP协议
- IP协议用于在IP主机之间发送/接收数据包,IP协议尽最大努力交付数据包。
13.5 IP数据包格式
IP数据包由IP头、发送方IP地址和接收方IP地址以及数据组成。每个IP数据包的大小最大为64KB。
13.12 网络编程
13.12.2 服务器-客户机计算模型
大多数网络编程任务都基于服务器-客户机计算模型。在服务器-客户机计算模财中我们首先在服务器主机上运行服务器进程。然后,我们从客户机主机运行客户机在UDP中,服务器等待来自客户机的数据报,处理数据报并生成对客户机的响应。在TCP中,服务器等待客户机连接。客户机首先连接到服务器,在客户机和服务器之间建立一个虚拟电路,建立连接后,服务器和客户机可以交换连续的数据流。
13.13 套接字编程
在网络编程中,TCP/IP的用户界面是通过一系列C语言库函数和系统调用来实现的, 这些函数和系统调用统称为套接字API (( Rago 1993; Stevens等2004 )。
13.13.1 套接字地址
struct sockaddr_in {
sa_family_t sin_family; // AF_INET for TCP/IP
in_port_t sin_port; // port number
struct in_addr sin_addr; // IP address
};
struct in_addr { // internet address
uint32_t s_addr; // IP address in network byte order
};
- TCP/IP 网络的 sin_family 始终设置为 AF_INET。
- sm_port包含按网络字节顺序排列的端口号。
- sin_addr是按网络字节顺序排列的主机IP地址。
13.13.2 套接字API
-
init套接字
//udp int udp_sock = socket(AF_INET, SOCK_DGRAM, 0); //tcp int tcp_sock = socket(AF_INET, SOCK_STRAM, 0);
-
int bind(int sockfd, struct sockaddr *addr, socklen_t addrlen)
-
UDP套接字
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen); ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);
-
TCP套接字
int listen(int sockfd, int backlog); int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
-
send()/read() and recv/write()
ssize_t send(int sockfd, const void *buf, size_t len, int flags); ssize_t write(sockfd, void *buf, size_t, len) ssize_t recv(int sockfd, void *buf, size_t len, int flags); ssize_t read(sockfd, void *buf, size_t len);
代码实践
参考书上的代码编写了UDP的server端和client端。
UDP
- server端代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#define BUFLEN 256
#define PORT 1234
char line[BUFLEN];
struct sockaddr_in me, client;
int sock, rlen, clen = sizeof(client);
int main(){
printf("1. create a UDP socket\n");
sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
printf("2. file me with server address and port number\n");
memset((char *)&me, 0, sizeof(me));
me.sin_family = AF_INET;
me.sin_port = htons(PORT);
me.sin_addr.s_addr = htonl(INADDR_ANY);
printf("3. bind socket to server IP and port\n");
bind(sock, (struct sockaddr*)&me, sizeof(me));
printf("4. wait for datagram\n");
while(1){
memset(line, 0, BUFLEN);
printf("UDP server: waiting for datagram\n");
rlen = recvfrom(sock, line, BUFLEN, 0, (struct sockaddr *)&client, &clen);
printf("recevied a datagram from [host:port] = [%s:%d]\n",
inet_ntoa(client.sin_addr), ntohs(client.sin_port));
printf("rlen=%d: line=%s\n", rlen, line);
printf("send reply\n");
sendto(sock, line, rlen, 0, (struct sockaddr*)&client, clen);
}
return 0;
}
- client端代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#define SERVER_HOST "127.0.0.1"
#define SERVER_PORT 1234
#define BUFLEN 256
char line[BUFLEN];
struct sockaddr_in server;
int sock, rlen, slen=sizeof(server);
int main(){
printf("1. create a UDP socket\n");
sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
printf("2. fill in server address and port number\n");
memset((char *) &server, 0, sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(SERVER_PORT);
inet_aton(SERVER_HOST, &server.sin_addr);
while(1){
printf("Enter a line :" );
fgets(line, BUFLEN, stdin);
line[strlen(line)-1] = 0;
printf("send line to server\n");
sendto(sock, line, strlen(line), 0, (struct sockaddr *)&server, slen);
memset(line, 0, BUFLEN);
printf("try to receive a line from server\n");
rlen = recvfrom(sock, line, BUFLEN, 0, (struct sockaddr *)&server, &slen);
printf("rlen=%d : line=%s\n", rlen, line);
}
return 0;
}
- 运行结果
TCP
- sever端代码
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#define MAX 256
#define SERVER_HOST "localhost"
#define SERVER_IP "127.0.0.1"
#define SERVER_PORT 1234
struct sockaddr_in server_addr, client_addr;
int mysock, csock; // socket descriptors
int r, len, n; // help variables
int server_init()
{
printf("================== server init ======================\n");
// create a TCP socket by socket() syscall
printf("1 : create a TCP STREAM socket\n");
mysock = socket(AF_INET, SOCK_STREAM, 0);
if (mysock < 0)
{
printf("socket call failed\n");
exit(1);
}
printf("2 : fill server_addr with host IP and PORT# info\n");
// initialize the server_addr structure
server_addr.sin_family = AF_INET; // for TCP/IP
server_addr.sin_addr.s_addr = htonl(INADDR_ANY); // This HOST IP
server_addr.sin_port = htons(SERVER_PORT); // port number 1234
printf("3 : bind socket to server address\n");
r = bind(mysock, (struct sockaddr *)&server_addr, sizeof(server_addr));
if (r < 0)
{
printf("bind failed\n");
exit(3);
}
printf(" hostname = %s port = %d\n", SERVER_HOST, SERVER_PORT);
printf("4 : server is listening ....\n");
listen(mysock, 5); // queue length = 5
printf("=================== init done =======================\n");
}
int main()
{
char line[MAX];
server_init();
while (1)
{ // Try to accept a client request
printf("server: accepting new connection ....\n");
// Try to accept a client connection as descriptor newsock
len = sizeof(client_addr);
csock = accept(mysock, (struct sockaddr *)&client_addr, &len);
if (csock < 0)
{
printf("server: accept error\n");
exit(1);
}
printf("server: accepted a client connection from\n");
printf("---------------------------------------------–\n");
printf("Clinet: IP=%s port=%d\n",
inet_ntoa(client_addr.sin_addr),
ntohs(client_addr.sin_port));
printf("---------------------------------------------–\n");
// Processing loop: client_sock <== data ==> client
while (1)
{
n = read(csock, line, MAX);
if (n == 0)
{
printf("server: client died, server loops\n");
close(csock);
break;
}
// show the line string
printf("server: read n=%d bytes; line=%s\n", n, line);
// echo line to client
n = write(csock, line, MAX);
printf("server: wrote n=%d bytes; ECHO=%s\n", n, line);
printf("server: ready for next request\n");
}
}
}
- client端代码
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netdb.h>
#define MAX 256
#define SERVER_HOST "localhost"
#define SERVER_PORT 1234
struct sockaddr_in server_addr;
int sock, r;
int client_init()
{
printf("======= clinet init ==========\n");
printf("1 : create a TCP socket\n");
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0)
{
printf("socket call failed\n");
exit(1);
}
printf("2 : fill server_addr with server’s IP and PORT#\n");
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY); // localhost
server_addr.sin_port = htons(SERVER_PORT); // server port number
printf("3 : connecting to server ....\n");
r = connect(sock, (struct sockaddr *)&server_addr, sizeof(server_addr));
if (r < 0)
{
printf("connect failed\n");
exit(3);
}
printf("4 : connected OK to\n");
printf("-------------------------------------------------------\n");
printf("Server hostname=%s PORT=%d\n", SERVER_HOST, SERVER_PORT);
printf("-------------------------------------------------------\n");
printf("========= init done ==========\n");
}
int main()
{
int n;
char line[MAX], ans[MAX];
client_init();
printf("******** processing loop *********\n");
while (1)
{
printf("input a line : ");
bzero(line, MAX); // zero out line[ ]
fgets(line, MAX, stdin); // get a line from stdin
line[strlen(line) - 1] = 0; // kill \n at end
if (line[0] == 0) // exit if NULL line
exit(0);
// Send line to server
n = write(sock, line, MAX);
printf("client: wrote n=%d bytes; line=%s\n", n, line);
// Read a line from sock and show it
n = read(sock, ans, MAX);
printf("client: read n=%d bytes; echo=%s\n", n, ans);
}
}
- 运行截图