Socket 由淺入深系列--------- 簡單實現程式設計(三)
socket 由淺入深 原理(一)介紹了一些,下面也就是簡單實現,並未考慮其他效能化!
使用TCP的伺服器客戶機舉例
伺服器
設定一個簡單的TCP伺服器涉及下列步驟:
呼叫 socket()建立套接字
呼叫Binding 把套接字繫結到一個監聽埠上。在呼叫 bind()之前, 程式必須宣告一個 sockaddr_in 結構體,用 memset()清除, and the sin_family (AF_INET), and fill its sin_port (the listening port, in network byte order) fields. Converting a short int to network byte order can be done by calling the function htons() (host to network short).
Preparing the socket to listen for connections (making it a listening socket), with a call to listen().
Accepting incoming connections, via a call to accept(). This blocks until an incoming connection is received, and then returns a socket descriptor for the accepted connection. The initial descriptor remains a listening descriptor, and accept() can be called again at any time with this socket, until it is closed.
Communicating with the remote host, which can be done through send() and recv() or write() and read().
Eventually closing each socket that was opened, once it is no longer needed, using close(). Note that if there were any calls to fork(), each process must close the sockets it knew about (the kernel keeps track of how many processes have a descriptor open), and two processes should not use the same socket at once.
/* Server code in C */
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main(void)
{
struct sockaddr_in stSockAddr;
int SocketFD = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if(-1 == SocketFD)
{
perror("can not create socket");
exit(EXIT_FAILURE);
}
memset(&stSockAddr, 0, sizeof(struct sockaddr_in));
stSockAddr.sin_family = AF_INET;
stSockAddr.sin_port = htons(1100);
stSockAddr.sin_addr.s_addr = INADDR_ANY;
if(-1 == bind(SocketFD,(const struct sockaddr *)&stSockAddr, sizeof(struct sockaddr_in)))
{
perror("error bind failed");
close(SocketFD);
exit(EXIT_FAILURE);
}
if(-1 == listen(SocketFD, 10))
{
perror("error listen failed");
close(SocketFD);
exit(EXIT_FAILURE);
}
for(;;)
{
int ConnectFD = accept(SocketFD, NULL, NULL);
if(0 > ConnectFD)
{
perror("error accept failed");
close(SocketFD);
exit(EXIT_FAILURE);
}
/* perform read write operations ... */
shutdown(ConnectFD, SHUT_RDWR);
close(ConnectFD);
}
close(SocketFD);
return 0;
}
客戶機
建立一個客戶機連線涉及以下步驟:
呼叫 socket()建立套接字。
用connect()連線到伺服器, passing a sockaddr_in structure with the sin_family set to AF_INET, sin_port set to the port the endpoint is listening (in network byte order), and sin_addr set to the IP address of the listening server (also in network byte order.)
用send() 和 recv() 或者 write() 和 read()進行通訊。
用close()終止連線。如果呼叫fork(), 每個程式都要用close()。
/* Client code in C */
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main(void)
{
struct sockaddr_in stSockAddr;
int Res;
int SocketFD = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if (-1 == SocketFD)
{
perror("cannot create socket");
exit(EXIT_FAILURE);
}
memset(&stSockAddr, 0, sizeof(struct sockaddr_in));
stSockAddr.sin_family = AF_INET;
stSockAddr.sin_port = htons(1100);
Res = inet_pton(AF_INET, "192.168.1.3", &stSockAddr.sin_addr);
if (0 > Res)
{
perror("error: first parameter is not a valid address family");
close(SocketFD);
exit(EXIT_FAILURE);
}
else if (0 == Res)
{
perror("char string (second parameter does not contain valid ipaddress");
close(SocketFD);
exit(EXIT_FAILURE);
}
if (-1 == connect(SocketFD, (const struct sockaddr *)&stSockAddr, sizeof(struct sockaddr_in)))
{
perror("connect failed");
close(SocketFD);
exit(EXIT_FAILURE);
}
/* perform read write operations ... */
shutdown(SocketFD, SHUT_RDWR);
close(SocketFD);
return 0;
}
使用UDP的伺服器客戶機舉例
使用者資料包協議(UDP)是一個不保證正確傳輸的無連線協議。 UDP資料包可能會亂序到達,多次到達或者直接丟失。但是設計的負載比TCP小。
UDP地址空間,也即是UDP埠,和TCP埠是沒有關係的。
伺服器
Code may set up a UDP server on port 7654 as follows:
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <unistd.h> /* for close() for socket */
#include <stdlib.h>
int main(void)
{
int sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
struct sockaddr_in sa;
char buffer[1024];
ssize_t recsize;
socklen_t fromlen;
memset(&sa, 0, sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_addr.s_addr = INADDR_ANY;
sa.sin_port = htons(7654);
if (-1 == bind(sock,(struct sockaddr *)&sa, sizeof(struct sockaddr)))
{
perror("error bind failed");
close(sock);
exit(EXIT_FAILURE);
}
for (;;)
{
printf ("recv test....\n");
recsize = recvfrom(sock, (void *)buffer, 1024, 0, (struct sockaddr *)&sa, &fromlen);
if (recsize < 0)
fprintf(stderr, "%s\n", strerror(errno));
printf("recsize: %d\n ",recsize);
sleep(1);
printf("datagram: %s\n",buffer);
}
}
上面的無限迴圈用recvfrom()接收給UDP埠7654的資料包。使用如下引數:
指向快取資料指標
快取大小
標誌
地址
地址結構體大小
客戶機
用UDP資料包傳送一個"Hello World!" 給地址127.0.0.1(迴環地址),埠 7654 。
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <unistd.h> /* for close() for socket */
int main(int argc, char *argv[])
{
int sock;
struct sockaddr_in sa;
int bytes_sent, buffer_length;
char buffer[200];
buffer_length = snprintf(buffer, sizeof buffer, "Hello World!");
sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (-1 == sock) /* if socket failed to initialize, exit */
{
printf("Error Creating Socket");
exit(EXIT_FAILURE);
}
memset(&sa, 0, sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_addr.s_addr = htonl(0x7F000001);
sa.sin_port = htons(7654);
bytes_sent = sendto(sock, buffer, buffer_length, 0,(struct sockaddr*)&sa, sizeof (struct sockaddr_in));
if (bytes_sent < 0)
printf("Error sending packet: %s\n", strerror(errno));
close(sock); /* close the socket */
return 0;
}
buffer指定要傳送資料的指標, buffer_length指定快取內容的大小。
linux scoket 由淺入深 詳解(四)
相關文章
- C#非同步程式設計由淺入深(三)細說AwaiterC#非同步程式設計AI
- C#非同步程式設計由淺入深(一)C#非同步程式設計
- promise由淺入深Promise
- MongoDB由淺入深MongoDB
- javascript由淺入深JavaScript
- 由淺入深 docker 系列: (6) 映象分層Docker
- 由淺入深 docker 系列: (2) docker 構建Docker
- 由淺入深 docker 系列: (5) 資源隔離Docker
- 由淺入深 docker 系列: (3) docker-composeDocker
- JavaScript Promise由淺入深JavaScriptPromise
- MySQL索引由淺入深MySql索引
- C#非同步程式設計由淺入深(二)Async/Await的作用.C#非同步程式設計AI
- 物件導向-由淺入深物件
- 由淺入深介紹 Redis LRU 策略的具體實現Redis
- 由淺入深 docker 系列:(4) 容器與虛擬機器Docker虛擬機
- 通過 Socket 實現 TCP 程式設計入門TCP程式設計
- 通過 Socket 實現 UDP 程式設計 入門UDP程式設計
- Socket程式設計入門(基於Java實現)程式設計Java
- 純手寫Promise,由淺入深Promise
- Vue.js 2.0 由淺入深Vue.js
- iOS架構由淺入深 | MVVMiOS架構MVVM
- 由淺入深理解 IOC 和 DI
- Git由淺入深之分支管理Git
- 由淺入深學python(一)Python
- 由淺入深的來聊聊Golang中select的實現機制Golang
- Git由淺入深之操作與指令Git
- 由淺入深理解Dubbo的SPI機制
- 由淺入深完全理解Java動態代理Java
- 由淺入深學C# 視訊教程C#
- 由淺入深學習JavaScript Debug技巧JavaScript
- Java 反射由淺入深 | 進階必備Java反射
- 通過socket實現DUP程式設計程式設計
- socket實現簡單ssh服務
- AI實戰 | 由淺入深,手把手帶你實現Java轉型學習助手AIJava
- Git 由淺入深之細說變基 (rebase)Git
- 第十八節:Skywalking由淺入深
- Rust 程式設計,實現簡單的佇列Rust程式設計佇列
- socket程式設計實戰程式設計