新聞中心
在計算機網(wǎng)絡(luò)中,Socket是一種實現(xiàn)網(wǎng)絡(luò)通信的缺省方式,它是網(wǎng)絡(luò)通信的接口,是我們進行數(shù)據(jù)交換和通信的基礎(chǔ)。Socket通信在Linux系統(tǒng)中得到廣泛應(yīng)用,本文將從流程角度出發(fā),圖解Linux上Socket通信的整個過程。

成都創(chuàng)新互聯(lián)堅持“要么做到,要么別承諾”的工作理念,服務(wù)領(lǐng)域包括:網(wǎng)站設(shè)計、成都做網(wǎng)站、企業(yè)官網(wǎng)、英文網(wǎng)站、手機端網(wǎng)站、網(wǎng)站推廣等服務(wù),滿足客戶于互聯(lián)網(wǎng)時代的獨山網(wǎng)站設(shè)計、移動媒體設(shè)計的需求,幫助企業(yè)找到有效的互聯(lián)網(wǎng)解決方案。努力成為您成熟可靠的網(wǎng)絡(luò)建設(shè)合作伙伴!
一、什么是Socket
在計算機網(wǎng)絡(luò)中,Socket是一種抽象概念,一種通信端口,是一個虛擬的門,是網(wǎng)絡(luò)通信的接口。在Linux系統(tǒng)中,Socket是一種文件描述符,可以像操作文件一樣讀寫,其中傳輸?shù)臄?shù)據(jù)源可以是文件、終端、網(wǎng)絡(luò)等。
二、Socket通信的基本流程
Socket通信的基本流程圖如下所示:

Socket通信的基本流程有以下幾步:
1. 創(chuàng)建Socket:創(chuàng)建通信的Socket,用于接收和發(fā)送數(shù)據(jù)。
2. 綁定Socket:將Socket與本地IP地址和端口號綁定,確定Socket的具體使用位置。
3. 監(jiān)聽Socket:Socket處于監(jiān)聽狀態(tài),等待客戶端的連接請求。
4. 接收連接:服務(wù)器端等待客戶端的請求連接,一旦收到請求連接,就接受客戶端的連接請求,并創(chuàng)建一個新的Socket進行通信。
5. 發(fā)送和接收數(shù)據(jù):客戶端和服務(wù)器端通過各自的Socket進行數(shù)據(jù)的發(fā)送和接收。
6. 關(guān)閉Socket:通信結(jié)束后,關(guān)閉Socket,釋放資源。
現(xiàn)在,我們將詳細解釋每一步。
三、Socket通信的詳細流程
1. 創(chuàng)建Socket
Socket創(chuàng)建通常使用socket()函數(shù),該函數(shù)的原型為:
“`c
#include
// family表示使用的協(xié)議族,type表示Socket類型,protocol表示使用的協(xié)議,一般為0
int socket(int family, int type, int protocol);
“`
其中,family表示使用的協(xié)議族,type表示Socket類型,protocol表示使用的協(xié)議,一般為0。
常見的family有:
– AF_INET:IPv4協(xié)議族
– AF_INET6:IPv6協(xié)議族
常見的type有:
– SOCK_STREAM:基于TCP協(xié)議的流Socket,用于傳輸可靠的字節(jié)流數(shù)據(jù)
– SOCK_DGRAM:基于UDP協(xié)議的數(shù)據(jù)報Socket,用于傳輸無連接的、不可靠的數(shù)據(jù)
常見的protocol有:
– IPPROTO_IP:協(xié)議無關(guān),通常為0
– IPPROTO_TCP:TCP協(xié)議,用于數(shù)據(jù)傳輸?shù)目煽啃?/p>
– IPPROTO_UDP:UDP協(xié)議,用于無連接的數(shù)據(jù)傳輸
2. 綁定Socket
綁定Socket通常使用bind()函數(shù),該函數(shù)的原型為:
“`c
#include
// sockfd表示要綁定的Socket,addr表示本地IP地址和端口號,addrlen表示地址長度
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
“`
其中,sockfd表示要綁定的Socket,addr表示本地IP地址和端口號,addrlen表示地址長度。
綁定Socket的目的是為Socket確定一個具體的位置,指定Socket使用的本地IP地址和端口號。
3. 監(jiān)聽Socket
監(jiān)聽Socket通常使用listen()函數(shù),該函數(shù)的原型為:
“`c
#include
// sockfd表示要監(jiān)聽的Socket,backlog表示等待連接隊列的長度
int listen(int sockfd, int backlog);
“`
其中,sockfd表示要監(jiān)聽的Socket,backlog表示等待連接隊列的長度。對于半連接狀態(tài)的Socket,即已經(jīng)接收到連接請求,但未完成連接的Socket,backlog無效。
4. 接收連接
接收連接通常使用accept()函數(shù),該函數(shù)的原型為:
“`c
#include
// sockfd表示要監(jiān)聽的Socket,addr表示客戶端的IP地址和端口號,addrlen表示地址長度
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
“`
其中,sockfd表示要監(jiān)聽的Socket,addr表示客戶端的IP地址和端口號,addrlen表示地址長度。
accept()函數(shù)是一個阻塞函數(shù),意味著程序會一直阻塞在這里,直到有客戶端的連接請求到來。當有客戶端的連接請求到來時,accept()函數(shù)返回一個新的Socket,用于和客戶端進行通信。客戶端的IP地址和端口號存儲在addr所指向的地址中。
5. 發(fā)送和接收數(shù)據(jù)
發(fā)送和接收數(shù)據(jù)需要使用send()和recv()函數(shù):
“`c
#include
#include
// sockfd表示Socket,buf表示發(fā)送或接收的數(shù)據(jù),len表示發(fā)送或接收的字節(jié)數(shù),flags表示數(shù)據(jù)的標志
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
“`
其中,sockfd表示Socket,buf表示發(fā)送或接收的數(shù)據(jù),len表示發(fā)送或接收的字節(jié)數(shù),flags表示數(shù)據(jù)的標志。
6. 關(guān)閉Socket
關(guān)閉Socket需要使用close()函數(shù),該函數(shù)的原型為:
“`c
#include
// sockfd表示要關(guān)閉的Socket
int close(int sockfd);
“`
四、
相關(guān)問題拓展閱讀:
- linux下socket 網(wǎng)絡(luò)編程(客戶端向服務(wù)器端發(fā)送文件) 求源代碼 大哥大姐幫幫忙 。。謝謝
linux下socket 網(wǎng)絡(luò)編程(客戶端向服務(wù)器端發(fā)送文件) 求源代碼 大哥大姐幫幫忙 。。謝謝
#include
#include
#include
#include
#include
#include
#include
main()
{
int serverfd=socket(AF_INET,SOCK_STREAM,0);
if(serverfd==-1) printf(“服務(wù)器socket建立失敗:%m\n”),exit(-1);
printf(“服務(wù)器socket建立成功!\n”);
struct sockaddr_in addr;
addr.sin_family=AF_INET;
addr.sin_port=htons(11112);
inet_aton(“192.168.180.92”,&addr.sin_addr);
int r=bind(serverfd,(struct sockaddr*)&addr,sizeof(addr));
if(r==-1) printf(“綁定地址失敗:%m\n”),exit(-1);
printf(“綁定地址成功!\悉哪n”);
r=listen(serverfd,10);
if(r==-1) printf(“監(jiān)聽服務(wù)socket變化失敗:%m\n”),exit(-1);
printf(“監(jiān)聽服務(wù)器socket成功!\n”);
struct sockaddr_in caddr;
socklen_t len;
while(1)
{
len=sizeof caddr;
int fd=accept(serverfd,(struct sockaddr*)&caddr,&len);
printf(“有人連接:%s:%d\n”,
inet_ntoa(caddr.sin_addr),
ntohs(caddr.sin_port));
}
}
這是服務(wù)器端睜櫻碼的,客戶端的只要去掉監(jiān)聽,連接,再把發(fā)送接收數(shù)據(jù)改一下,就能用了
server:
#include
#include
#include
#include
#include 鏈唯嘩
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define MAXDATASIZE
#define SERVPORT
#define BACKLOG 10
int SendFileToServ(const char *path, const char *FileName, const char *ip)
{
#define PORT 20232
int sockfd;
int recvbytes;
char buf;
char send_str;
char filepath = {0};
struct sockaddr_in serv_addr;
FILE *fp;
sprintf(filepath, “%s%s”, path, FileName);
if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)
{
perror(“socket”山纖);
return 1;
}
bzero(&serv_addr,sizeof(struct sockaddr_in));
serv_addr.sin_family=AF_INET;
serv_addr.sin_port=htons(PORT);
inet_aton(ip, &serv_addr.sin_addr);
int IErrCount = 0;
again:
if(connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(struct sockaddr))==-1)
{
if (5 == IErrCount)
return 1;
IErrCount++;
perror(“connect”);
sleep(2);
goto again;
}
//if ((fp = fopen(FileName, “rb”)) == NULL)
if ((fp = fopen(filepath, “rb”)) == NULL)
{
perror(“fopen “);
return 1;
}
recvbytes = write(sockfd, FileName, strlen(FileName));
recvbytes = read(sockfd, buf, MAXDATASIZE);
if (!memcmp(buf, “sendmsg”, 7))
{
while(fgets(send_str, MAXDATASIZE, fp))
{
recvbytes = write(sockfd, send_str, strlen(send_str));
recvbytes = read(sockfd, buf, MAXDATASIZE);
if (recvbytes 0)
{
nret = SendFileToServ(path, FileName, str);
printf(“nret\n”, nret);
if (1 == nret)
write(client_fd, “send file error”, 15);
else if(2 == nret)
write(client_fd, “reload nginx error”, 18);
else
write(client_fd, “succ”, 4);
}
close(client_fd);
}
}
_________________________________________________
client:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define MAXDATASIZE
#define SERVPORT 20232
#define BACKLOG 10
int mysyslog(const char * msg)
{
FILE *fp;
if ((fp = fopen(“/tmp/tmp.log”, “a+”)) == NULL)
{
return 0;
}
fprintf(fp, “\n”, msg);
fclose(fp);
return 0;
}
static void quit_handler(int signal)
{
kill(0, SIGUSR2);
syslog( LOG_NOTICE, “apuserv quit…”);
// do something exit thing ,such as close socket ,close mysql,free list
// …..
//i end
exit(0);
}
static int re_conf = 0;
static void reconf_handler(int signal)
{
re_conf=1;
syslog(LOG_NOTICE,”apuserv reload configure file .”);
// ????·???????1nf == 1£???′μ?????
static int isrunning(void)
{
int fd;
int ret;
struct flock lock;
lock.l_type = F_WRLCK;
lock.l_whence = 0;
lock.l_start = 0;
lock.l_len = 0;
const char *lckfile = “/tmp/dstserver.lock”;
fd = open(lckfile,O_WRON|O_CREAT);
if (fd < 0) {
syslog(LOG_ERR,”can not create lock file: %s\n”,lckfile);
return 1;
}
if ((ret = fcntl(fd,F_SETLK,&lock)) < 0) {
ret = fcntl(fd,F_GETLK,&lock);
if (lock.l_type != F_UNLCK) {
close(fd);
return lock.l_pid;
}
else {
fcntl(fd,F_SETLK,&lock);
}
}
return 0;
}
int main(int argc, char **argv)
{
int sockfd,client_fd;
socklen_t sin_size;
struct sockaddr_in my_addr,remote_addr;
char buff;
int recvbytes;
#if 1
int pid ;
char ch ;
int ret;
int debug = 0;
signal(SIGUSR1, SIG_IGN);
signal(SIGUSR2, SIG_IGN);
signal(SIGHUP, SIG_IGN);
signal(SIGTERM, quit_handler);
syslog(LOG_NOTICE,”dstserver start….”);
while ((ch = getopt(argc, argv, “dhV”)) != -1) {
switch (ch) {
case ‘d’:
debug = 1;
break;
case ‘V’:
printf(“Version:%s\n”,”1.0.0″);
return 0;
case ‘h’:
printf(” -d use daemon mode\n”);
printf(” -V show version\n”);
return 0;
default:
printf(” -d use daemon mode\n”);
printf(” -V show version\n”);
}
}
if (debug && daemon(0,0 ) ) {
return -1;
}
if (isrunning()) {
fprintf(stderr, “dstserver is already running\n”);
syslog(LOG_INFO,”dstserver is already running\n”);
exit(0);
}
while (1) {
pid = fork();
if (pid < 0)
return -1;
if (pid == 0)
break;
while ((ret = waitpid(pid, NULL, 0)) != pid) {
syslog(LOG_NOTICE, “waitpid want %d, but got %d”, pid, ret);
if (ret < 0)
syslog(LOG_NOTICE, “waitpid errno:%d”, errno);
}
kill(0, SIGUSR2);
sleep(1);
syslog(LOG_NOTICE,”restart apuserver”);
}
signal(SIGHUP, reconf_handler);
signal(SIGPIPE, SIG_IGN);
signal(SIGUSR1,SIG_IGN);
signal(SIGUSR2, SIG_DFL);
signal(SIGTERM, SIG_DFL);
#endif
if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)
{
perror(“socket”);
exit(1);
}
bzero(&my_addr,sizeof(struct sockaddr_in));
my_addr.sin_family=AF_INET;
my_addr.sin_port=htons(SERVPORT);
my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
if(bind(sockfd,(struct sockaddr *)&my_addr,sizeof(struct sockaddr))==-1)
{
perror(“bind”);
exit(1);
}
if(listen(sockfd,BACKLOG)==-1)
{
perror(“l(fā)isten”);
exit(1);
}
char filepath= {0};
FILE *fp;
while(1)
{
sin_size = sizeof(struct sockaddr_in);
if((client_fd = accept(sockfd, (struct sockaddr *)&remote_addr, &sin_size))==-1)
{
perror(“falied accept”);
continue;
}
memset(buff, 0, MAXDATASIZE);
recvbytes = read(client_fd, buff, MAXDATASIZE);
sprintf(filepath, “/etc/nginx/url_rule/%s”, buff);
if ((fp = fopen(filepath, “wb”)) == NULL)
{
perror(“fopen”);
close(client_fd);
continue;
}
write(client_fd, “sendmsg”, 7);
while(read(client_fd, buff, MAXDATASIZE))
{
if (!memcmp(buff, “end”, 3))
{
fclose(fp);
break;
}
else
{
fprintf(fp, “%s”, buff);
write(client_fd, “goon”, 4);
}
}
//system(“nginx -s reload”);
char *Sptr = “nginx reload succ”;
char *Eptr = “nginx reload error”;
int ret;
ret = system(“nginx -s reload”);
printf(“ret\n”, ret);
if (ret != 0)
{
write(client_fd, Eptr, strlen(Eptr));
}
else
{
write(client_fd, Sptr, strlen(Sptr));
}
close(client_fd);
}
}
以前寫的:內(nèi)容忘記了。不是很復(fù)雜你可以自己看!
成都創(chuàng)新互聯(lián)建站主營:成都網(wǎng)站建設(shè)、網(wǎng)站維護、網(wǎng)站改版的網(wǎng)站建設(shè)公司,提供成都網(wǎng)站制作、成都網(wǎng)站建設(shè)、成都網(wǎng)站推廣、成都網(wǎng)站優(yōu)化seo、響應(yīng)式移動網(wǎng)站開發(fā)制作等網(wǎng)站服務(wù)。
網(wǎng)頁題目:「圖解」Linux上Socket通信的流程(linuxsocket通信流程圖)
轉(zhuǎn)載來源:http://m.fisionsoft.com.cn/article/cddsgce.html


咨詢
建站咨詢
