夜鹰教程网-程序员的加油站
 当前位置:文章中心 >> Winform/客户端程序
C# socket 多线程多管道可断点传送大文件
夜鹰教程网 来源:www.yyjcw.com 日期:2017-11-17 10:20:54
C# socket 多线程多管道可断点传送大文件

这里只发布核心代码。源码及测试程序请点这里下载,谢谢。

有啥BUG,问题请发送email至ilovehaley.kid@gmail.com ,谢谢。:D

 

 1 #define Sleep
 2  //#undef Sleep
 3  //#define TransmitLog
 4  #undef TransmitLog
 5  //#define BreakpointLog
 6  #undef BreakpointLog
 7 using System;
 8 using System.Net;
 9 using System.Net.Sockets;
10 using System.IO;
11 using System.Text;
12 using System.Threading;
13 using System.Collections.Generic;
14 using System.Diagnostics;
15
16 namespace Rocky
17 {
18    public static class FileTransmiter
19    {
20        #region NestedType
21        private class SendWorker : IWorker
22        {
23            private long totalSent, totalSend;
24            private byte[] buffer;
25            private Socket sock;
26            private FileStream reader;
27            private Thread thread;
28            private bool isFinished;
29
30            public long TotalSent
31            {
32                get { return totalSent; }
33            }
34            public long TotalSend
35            {
36                get { return totalSend; }
37            }
38            public byte[] Buffer
39            {
40                get { return buffer; }
41            }
42            public Socket Client
43            {
44                get { return sock; }
45            }
46            public bool IsFinished
47            {
48                get { return isFinished; }
49            }
50
51            public SendWorker(IPEndPoint ip)
52            {
53                sock = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
54                sock.Connect(ip);
55                buffer = new byte[BufferSize];
56            }
57            public void Initialize(string path, long position,

long length)
58            {
59                Initialize(path, position, length, 0L, length);
60            }
61            public void Initialize(string path, long position,
 
long length, long worked, long total)
62            {
63                reader = new FileStream(path, FileMode.Open,
 FileAccess.Read, FileShare.Read);
64                reader.Position = position + worked;
65                totalSent = worked;
66                totalSend = total;
67                thread = new Thread(new ParameterizedThreadStart(Work));
68                thread.IsBackground = true;
69 #if TransmitLog
70                thread.Name = position.ToString() + length.ToString();
71                AppendTransmitLog(LogType.Transmit, thread.Name +

" Initialized:" + totalSent + "/" + totalSend + ".");
72 #endif
73            }
74            private void Work(object obj)
75            {
76                int read, sent;
77                bool flag;
78                while (totalSent < totalSend)
79                {
80                    read = reader.Read(buffer, 0, Math.Min(BufferSize,
(
int)(totalSend - totalSent)));
81                    sent = 0;
82                    flag = true;
83                    while ((sent += sock.Send(buffer, sent, read,
 SocketFlags.None))
< read)
84                    {
85                        flag = false;
86                        totalSent += (long)sent;
87 #if TransmitLog
88                        AppendTransmitLog(LogType.Transmit, thread.Name
                       
+ ":" + totalSent + "/" + totalSend + ".");
89 #endif
90 #if Sleep
91                        Thread.Sleep(200);
92 #endif
93                    }
94                    if (flag)
95                    {
96                        totalSent += (long)read;
97 #if TransmitLog
98                        AppendTransmitLog(LogType.Transmit, thread.Name
                       
+ ":" + totalSent + "/" + totalSend + ".");
99 #endif
100 #if Sleep
101                        Thread.Sleep(200);
102 #endif
103                    }
104                }
105                reader.Dispose();
106                sock.Shutdown(SocketShutdown.Both);
107                sock.Close();
108                EventWaitHandle waitHandle = obj as EventWaitHandle;
109                if (waitHandle != null)
110                {
111                    waitHandle.Set();
112                }
113                isFinished = true;
114            }
115
116            public void ReportProgress(out long worked, out long total)
117            {
118                worked = totalSent;
119                total = totalSend;
120            }
121
122            public void RunWork(EventWaitHandle waitHandle)
123            {
124                thread.Start(waitHandle);
125            }
126        }
127
128        private class ReceiveWorker : IWorker
129        {
130            private long offset, totalReceived, totalReceive;
131            private byte[] buffer;
132            private Socket sock;
133            private FileStream writer;
134            private Thread thread;
135            private bool isFinished;
136
137            public long TotalReceived
138            {
139                get { return totalReceived; }
140            }
141            public long TotalReceive
142            {
143                get { return totalReceive; }
144            }
145            public byte[] Buffer
146            {
147                get { return buffer; }
148            }
149            public Socket Client
150            {
151                get { return sock; }
152            }
153            public bool IsFinished
154            {
155                get { return isFinished; }
156            }
157
158            public ReceiveWorker(Socket client)
159            {
160                sock = client;
161                buffer = new byte[BufferSize];
162            }
163            public void Initialize(string path, long position, long length)
164            {
165                Initialize(path, position, length, 0L, length);
166            }
167            public void Initialize(string path, long position, long length,
 
long worked, long total)
168            {
169                writer = new FileStream(path, FileMode.Open,
 FileAccess.Write, FileShare.Write);
170                writer.Position = position + worked;
171                writer.Lock(position, length);
172                offset = position;
173                totalReceived = worked;
174                totalReceive = total;
175                thread = new Thread(new ParameterizedThreadStart(Work));
176                thread.IsBackground = true;
177 #if TransmitLog
178                thread.Name = position.ToString() + length.ToString();
179                AppendTransmitLog(LogType.Transmit, thread.Name
               
+ " Initialized:" + totalReceived + "/" + totalReceive + ".");
180 #endif
181            }
182            private void Work(object obj)
183            {
184                int received;
185                while (totalReceived < totalReceive)
186                {
187                    if ((received = sock.Receive(buffer)) == 0)
188                    {
189                        break;
190                    }
191                    writer.Write(buffer, 0, received);
192                    writer.Flush();
193                    totalReceived += (long)received;
194 #if TransmitLog
195                    AppendTransmitLog(LogType.Transmit, thread.Name +

":" + totalReceived + "/" + totalReceive + ".");
196 #endif
197 #if Sleep
198                    Thread.Sleep(200);
199 #endif
200                }
201                writer.Unlock(offset, totalReceive);
202                writer.Dispose();
203                sock.Shutdown(SocketShutdown.Both);
204                sock.Close();
205                EventWaitHandle waitHandle = obj as EventWaitHandle;
206                if (waitHandle != null)
207                {
208                    waitHandle.Set();
209                }
210                isFinished = true;
211            }
212
213            public void ReportProgress(out long worked, out long total)
214            {
215                worked = totalReceived;
216                total = totalReceive;
217            }
218
219            public void RunWork(EventWaitHandle waitHandle)
220            {
221                thread.Start(waitHandle);
222            }
223        }
224
225        private interface IWorker
226        {
227            bool IsFinished { get; }
228            void Initialize(string path, long position, long length);
229            void Initialize(string path, long position, long length,
 
long worked, long total);
230            void ReportProgress(out long worked, out long total);
231            void RunWork(EventWaitHandle waitHandle);
232        }
233        #endregion
234
235        #region Field
236        public const int BufferSize = 1024;
237        public const int PerLongCount = sizeof(long);
238        public const int MinThreadCount = 1;
239        public const int MaxThreadCount = 9;
240        public const string PointExtension = ".dat";
241        public const string TempExtension = ".temp";
242        private const long SplitSize = 1024L * 1024L * 100L;
243        public static readonly IPEndPoint TestIP;
244 #if TransmitLog
245        private static StreamWriter transmitLoger;
246 #endif
247 #if BreakpointLog
248        private static StreamWriter breakpointLoger;
249 #endif
250        #endregion
251
252        #region Constructor
253        static FileTransmiter()
254        {
255            AppDomain.CurrentDomain.UnhandledException +=

new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
256            TestIP = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 520);
257 #if TransmitLog
258            transmitLoger = new StreamWriter(Path.Combine(
AppDomain.CurrentDomain.BaseDirectory,
"transmit.log"), true, Encoding.Default);
259 #endif
260 #if BreakpointLog
261            breakpointLoger = new StreamWriter(Path.Combine(
AppDomain.CurrentDomain.BaseDirectory,
"breakpoint.log"), true, Encoding.Default);
262 #endif
263        }
264
265        static void CurrentDomain_UnhandledException(object sender,
 UnhandledExceptionEventArgs e)
266        {
267            StreamWriter writer = new StreamWriter(Path.Combine(
AppDomain.CurrentDomain.BaseDirectory,
"exec.log"), true, Encoding.Default);
268            writer.Write("Time:");
269            writer.Write(DateTime.Now.ToShortTimeString());
270            writer.Write(". ");
271            writer.WriteLine(e.ExceptionObject);
272            writer.Dispose();
273        }
274
275        #region Log
276 #if TransmitLog || BreakpointLog
277        public enum LogType
278        {
279            Transmit,
280            Breakpoint
281        }
282
283        public static void AppendTransmitLog(LogType type, string msg)
284        {
285            switch (type)
286            {
287                case LogType.Transmit:
288 #if TransmitLog
289                    transmitLoger.Write(DateTime.Now.ToShortTimeString());
290                    transmitLoger.Write('\t');
291                    transmitLoger.WriteLine(msg);
292                    transmitLoger.Flush();
293 #endif
294                    break;
295                case LogType.Breakpoint:
296 #if BreakpointLog
297                    breakpointLoger.Write(DateTime.Now.ToShortTimeString());
298                    breakpointLoger.Write('\t');
299                    breakpointLoger.WriteLine(msg);
300                    breakpointLoger.Flush();
301 #endif
302                    break;
303            }
304        }
305 #endif
306        #endregion
307        #endregion
308
309        #region Single
310        public static void Send(IPEndPoint ip, string path)
311        {
312            Stopwatch watcher = new Stopwatch();
313            watcher.Start();
314            Socket sock = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
315            sock.Connect(ip);
316            byte[] buffer = new byte[BufferSize];
317            using (FileStream reader = new FileStream(path,
FileMode.Open, FileAccess.Read, FileShare.None))
318            {
319                long send, length = reader.Length;
320                Buffer.BlockCopy(BitConverter.GetBytes(length),
               
0, buffer, 0, PerLongCount);
321                string fileName = Path.GetFileName(path);
322                sock.Send(buffer, 0, PerLongCount +

Encoding.Default.GetBytes(fileName, 0, fileName.Length,
buffer, PerLongCount), SocketFlags.None);
323                Console.WriteLine("Sending file:" +
fileName
+ ".Plz wait...");
324                sock.Receive(buffer);
325                reader.Position = send = BitConverter.ToInt64(buffer, 0);
326 #if BreakpointLog
327                Console.WriteLine("Breakpoint " + reader.Position);
328 #endif
329                int read, sent;
330                bool flag;
331                while ((read = reader.Read(buffer, 0, BufferSize)) != 0)
332                {
333                    sent = 0;
334                    flag = true;
335                    while ((sent += sock.Send(buffer, sent, read,
SocketFlags.None))
< read)
336                    {
337                        flag = false;
338                        send += (long)sent;
339 #if TransmitLog
340                        Console.WriteLine("Sent " + send + "/" + length + ".");
341 #endif
342 #if Sleep
343                        Thread.Sleep(200);
344 #endif
345                    }
346                    if (flag)
347                    {
348                        send += (long)read;
349 #if TransmitLog
350                        Console.WriteLine("Sent " + send + "/" + length + ".");
351 #endif
352 #if Sleep
353                        Thread.Sleep(200);
354 #endif
355                    }
356                }
357            }
358            sock.Shutdown(SocketShutdown.Both);
359            sock.Close();
360            watcher.Stop();
361            Console.WriteLine("Send finish.Span Time:" +
watcher.Elapsed.TotalMilliseconds
+ " ms.");
362        }
363
364        public static void Receive(IPEndPoint ip, string path)
365        {
366            Socket listener = new Socket(AddressFamily.InterNetwork,
 SocketType.Stream, ProtocolType.Tcp);
367            listener.Bind(ip);
368            listener.Listen(MinThreadCount);
369            Socket client = listener.Accept();
370            Stopwatch watcher = new Stopwatch();
371            watcher.Start();
372            byte[] buffer = new byte[BufferSize];
373            int received = client.Receive(buffer);
374            long receive, length = BitConverter.ToInt64(buffer, 0);
375            string fileName = Encoding.Default.GetString(buffer,
PerLongCount, received
- PerLongCount);
376            Console.WriteLine("Receiveing file:" + fileName + ".Plz wait...");
377            FileInfo file = new FileInfo(Path.Combine(path, fileName));
378            using (FileStream writer = file.Open(file.Exists ?
FileMode.Append : FileMode.CreateNew, FileAccess.Write, FileShare.None))
379            {
380                receive = writer.Length;
381                client.Send(BitConverter.GetBytes(receive));
382 #if BreakpointLog
383                Console.WriteLine("Breakpoint " + receive);
384 #endif
385                while (receive < length)
386                {
387                    if ((received = client.Receive(buffer)) == 0)
388                    {
389                        Console.WriteLine("Send Stop.");
390                        return;
391                    }
392                    writer.Write(buffer, 0, received);
393                    writer.Flush();
394                    receive += (long)received;
395 #if TransmitLog
396                    Console.WriteLine("Received " + receive + "/" + length + ".");
397 #endif
398 #if Sleep
399                    Thread.Sleep(200);
400 #endif
401                }
402            }
403            client.Shutdown(SocketShutdown.Both);
404            client.Close();
405            watcher.Stop();
406            Console.WriteLine("Receive finish.Span Time:" +
watcher.Elapsed.TotalMilliseconds
+ " ms.");
407        }
408        #endregion
409
410        #region Supper
411        #region Extensions
412        private static int ReportProgress(this IWorker[] workers,

out long worked, out long total)
413        {
414            worked = total = 0L;
415            long w, t;
416            foreach (IWorker worker in workers)
417            {
418                worker.ReportProgress(out w, out t);
419                worked += w;
420                total += t;
421            }
422            return (int)(worked / total) * 100;
423        }
424        private static int ReportSpeed(this IWorker[] workers, ref long oldValue)
425        {
426            long w, t;
427            workers.ReportProgress(out w, out t);
428            int speed = (int)((w - oldValue) / 8L);
429            oldValue = w;
430            return speed;
431        }
432        private static bool IsAllFinished(this IWorker[] workers)
433        {
434            bool flag = true;
435            foreach (IWorker worker in workers)
436            {
437                if (!worker.IsFinished)
438                {
439                    flag = false;
440                    break;
441                }
442            }
443            return flag;
444        }
445        #endregion
446
447        #region Helper
448        public static void Write(long value, byte[] buffer, int offset)
449        {
450            buffer[offset++] = (byte)value;
451            buffer[offset++] = (byte)(value >> 8);
452            buffer[offset++] = (byte)(value >> 0x10);
453            buffer[offset++] = (byte)(value >> 0x18);
454            buffer[offset++] = (byte)(value >> 0x20);
455            buffer[offset++] = (byte)(value >> 40);
456            buffer[offset++] = (byte)(value >> 0x30);
457            buffer[offset] = (byte)(value >> 0x38);
458        }
459        public static void Read(out long value, byte[] buffer, int offset)
460        {
461            uint num = (uint)(((buffer[offset++] | (buffer[offset++] << 8)) |
(buffer[offset
++] << 0x10)) | (buffer[offset++] << 0x18));
462            uint num2 = (uint)(((buffer[offset++] | (buffer[offset++] << 8)) |
(buffer[offset
++] << 0x10)) | (buffer[offset] << 0x18));
463            value = (long)((num2 << 0x20) | num);
464        }
465        #endregion
466
467        public static int GetThreadCount(long fileSize)
468        {
469            int count = (int)(fileSize / SplitSize);
470            if (count < MinThreadCount)
471            {
472                count = MinThreadCount;
473            }
474            else if (count > MaxThreadCount)
475            {
476                count = MaxThreadCount;
477            }
478            return count;
479        }
480
481        public static void SupperSend(IPEndPoint ip, string path)
482        {
483            Stopwatch watcher = new Stopwatch();
484            watcher.Start();
485            FileInfo file = new FileInfo(path);
486 #if DEBUG
487            if (!file.Exists)
488            {
489                throw new FileNotFoundException();
490            }
491 #endif
492            SendWorker worker = new SendWorker(ip);
493            long fileLength = file.Length;
494            Buffer.BlockCopy(BitConverter.GetBytes(fileLength), 0,
worker.Buffer,
0, PerLongCount);
495            string fileName = file.Name;
496            worker.Client.Send(worker.Buffer, 0, PerLongCount +
Encoding.Default.GetBytes(fileName,
0, fileName.Length, worker.Buffer,
PerLongCount), SocketFlags.None);
497            Console.WriteLine("Sending file:" + fileName + ".Plz wait...");
498            int threadCount = GetThreadCount(fileLength);
499            SendWorker[] workers = new SendWorker[threadCount];
500            for (int i = 0; i < threadCount; i++)
501            {
502                workers[i] = i == 0 ? worker : new SendWorker(ip);
503            }
504            #region Breakpoint
505            int perPairCount = PerLongCount * 2,
count
= perPairCount * threadCount;
506            byte[] bufferInfo = new byte[count];
507            long oddSize, avgSize = Math.DivRem(fileLength,
(
long)threadCount, out oddSize);
508            if (worker.Client.Receive(bufferInfo) == 4)
509            {
510                for (int i = 0; i < threadCount; i++)
511                {
512                    workers[i].Initialize(path, i * avgSize,
i
== threadCount - 1 ? avgSize + oddSize : avgSize);
513                }
514            }
515            else
516            {
517                long w, t;
518                for (int i = 0; i < threadCount; i++)
519                {
520                    Read(out w, bufferInfo, i * perPairCount);
521                    Read(out t, bufferInfo, i * perPairCount + PerLongCount);
522                    workers[i].Initialize(path, i * avgSize,
i
== threadCount - 1 ? avgSize + oddSize : avgSize, w, t);
523 #if BreakpointLog
524                    AppendTransmitLog(LogType.Breakpoint, i + " read:" + w + "/" + t + ".");
525 #endif
526                }
527            }
528            Thread.Sleep(200);
529            #endregion
530            AutoResetEvent reset = new AutoResetEvent(true);
531            for (int i = 0; i < threadCount; i++)
532            {
533                workers[i].RunWork(i == threadCount - 1 ? reset : null);
534            }
535            reset.WaitOne();
536            #region Breakpoint
537            int speed;
538            long value = 0L;
539            do
540            {
541                speed = workers.ReportSpeed(ref value);
542                Console.WriteLine("waiting for other threads. Progress:"

+ value + "/" + fileLength + ";Speed:" + speed + "kb/s.");
543                Thread.Sleep(1000);
544            }
545            while (!workers.IsAllFinished());
546            speed = workers.ReportSpeed(ref value);
547            Console.WriteLine("waiting for other threads. Progress:" +
value
+ "/" + fileLength + ";Speed:" + speed + "kb/s.");
548            #endregion
549            watcher.Stop();
550            Console.WriteLine("Send finish.Span Time:" +
watcher.Elapsed.TotalMilliseconds
+ " ms.");
551        }
552
553        public static void SupperReceive(IPEndPoint ip, string path)
554        {
555            Socket listener = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
556            listener.Bind(ip);
557            listener.Listen(MaxThreadCount);
558            ReceiveWorker worker = new ReceiveWorker(listener.Accept());
559            Stopwatch watcher = new Stopwatch();
560            watcher.Start();
561            int recv = worker.Client.Receive(worker.Buffer);
562            long fileLength = BitConverter.ToInt64(worker.Buffer, 0);
563            string fileName = Encoding.Default.GetString(worker.Buffer,
PerLongCount, recv
- PerLongCount);
564            Console.WriteLine("Receiveing file:" + fileName + ".Plz wait...");
565            int threadCount = GetThreadCount(fileLength);
566            ReceiveWorker[] workers = new ReceiveWorker[threadCount];
567            for (int i = 0; i < threadCount; i++)
568            {
569                workers[i] = i == 0 ? worker : new ReceiveWorker(listener.Accept());
570            }
571            #region Breakpoint
572            int perPairCount = PerLongCount * 2, count = perPairCount * threadCount;
573            byte[] bufferInfo = new byte[count];
574            string filePath = Path.Combine(path, fileName), pointFilePath =
Path.ChangeExtension(filePath, PointExtension), tempFilePath
=
Path.ChangeExtension(filePath, TempExtension);
575            FileStream pointStream;
576            long oddSize, avgSize = Math.DivRem(fileLength,
(
long)threadCount, out oddSize);
577            if (File.Exists(pointFilePath) && File.Exists(tempFilePath))
578            {
579                pointStream = new FileStream(pointFilePath,
FileMode.Open, FileAccess.ReadWrite, FileShare.None);
580                pointStream.Read(bufferInfo, 0, count);
581                long w, t;
582                for (int i = 0; i < threadCount; i++)
583                {
584                    Read(out w, bufferInfo, i * perPairCount);
585                    Read(out t, bufferInfo, i * perPairCount + PerLongCount);
586                    workers[i].Initialize(tempFilePath, i * avgSize,
 i
== threadCount - 1 ? avgSize + oddSize : avgSize, w, t);
587 #if BreakpointLog
588                    AppendTransmitLog(LogType.Breakpoint, i + " read:" + w + "/" + t + ".");
589 #endif
590                }
591                worker.Client.Send(bufferInfo);
592            }
593            else
594            {
595                pointStream = new FileStream(pointFilePath, FileMode.CreateNew,
FileAccess.ReadWrite, FileShare.None);
596                FileStream stream = new FileStream(tempFilePath, FileMode.CreateNew,
FileAccess.Write, FileShare.Write);
597                stream.SetLength(fileLength);
598                stream.Flush();
599                stream.Dispose();
600                for (int i = 0; i < threadCount; i++)
601                {
602                    workers[i].Initialize(tempFilePath, i * avgSize, i ==
threadCount
- 1 ? avgSize + oddSize : avgSize);
603                }
604                worker.Client.Send(bufferInfo, 0, 4, SocketFlags.None);
605            }
606            Timer timer = new Timer(state =>
607            {
608                long w, t;
609                for (int i = 0; i < threadCount; i++)
610                {
611                    workers[i].ReportProgress(out w, out t);
612                    Write(w, bufferInfo, i * perPairCount);
613                    Write(t, bufferInfo, i * perPairCount + PerLongCount);
614 #if BreakpointLog
615                    AppendTransmitLog(LogType.Breakpoint, i +
" write:" + w + "/" + t + ".");
616 #endif
617                }
618                pointStream.Position = 0L;
619                pointStream.Write(bufferInfo, 0, count);
620                pointStream.Flush();
621
622            }, null, TimeSpan.Zero, TimeSpan.FromSeconds(2));
623            #endregion
624            AutoResetEvent reset = new AutoResetEvent(true);
625            for (int i = 0; i < threadCount; i++)
626            {
627                workers[i].RunWork(i == threadCount - 1 ? reset : null);
628            }
629            reset.WaitOne();
630            #region Breakpoint
631            int speed;
632            long value = 0L;
633            do
634            {
635                speed = workers.ReportSpeed(ref value);
636                Console.WriteLine("waiting for other threads. Progress:" +
value
+ "/" + fileLength + ";Speed:" + speed + "kb/s.");
637                Thread.Sleep(1000);
638            }
639            while (!workers.IsAllFinished());
640            speed = workers.ReportSpeed(ref value);
641            Console.WriteLine("waiting for other threads. Progress:" +
value
+ "/" + fileLength + ";Speed:" + speed + "kb/s.");
642            timer.Dispose();
643            pointStream.Dispose();
644            File.Delete(pointFilePath);
645            File.Move(tempFilePath, filePath);
646            #endregion
647            watcher.Stop();
648            Console.WriteLine("Receive finish.Span Time:" +
watcher.Elapsed.TotalMilliseconds
+ " ms.");
649        }
650        #endregion
651    }
652 }

复制代码

 

PS:
  1、通过测试发现多线程stream.Flush()的地方会阻塞,

可以尝试增大stream的缓冲区或手动管理调用stream的Flush()。
  2、断点测试方法:先打开Server端,然后打开Client端发送;

中途任意关闭一端,再重复前一步即可。

复制链接 网友评论 收藏本文 关闭此页
上一条: C# Task 任务计划  下一条: 让ListBox的滚动条滚动到最底部
夜鹰教程网成立于2008年,目前已经运营了将近 13 年,发布了大量关于 html5/css3/C#/asp.net/java/python/nodejs/mongodb/sql server/android/javascript/mysql/mvc/easyui/vue/echarts原创教程。 我们一直都在坚持的是:认证负责、一丝不苟、以工匠的精神来打磨每一套教程,让读者感受到作者的用心。我们默默投入的时间,确保每一套教程都是一件作品,而不是呆板的文字和视频! 目前我们推出在线辅导班试运营,模式为一对一辅导,教学工具为QQ。我们的辅导学科包括 java 、android原生开发、webapp开发、商城开发、C#和asp.net开发,winform和物联网开发、web前端开发,但不仅限于此。 普通班针对的是国内学员,例如想打好基础的大学生、想转行的有志青年、想深入学习的程序员、想开发软件的初学者或者业余爱好者等。 就业办针对即将毕业上岗的大四学生,或者打算转行的初级开发工程师。 留学生班针对的是在欧美、加拿大、澳洲、日本、韩国、新加坡等地留学的中国学子,目的是让大家熟练地掌握编程技能,按时完成老师布置的作业,并能顺利地通过考试。 详细咨询QQ:1416759661   夜鹰教程网  基于角色的权限管理系统(c-s/b-s)。
  夜鹰教程网  基于nodejs的聊天室开发视频教程
  夜鹰教程网  Git分布式版本管理视频教程
  夜鹰教程网  MVC+EasyUI视频教程
  夜鹰教程网  在线考试系统视频教程
  夜鹰教程网  MongoDB视频教程。
  夜鹰教程网 Canvas视频教程
  夜鹰教程网 报表开发视频教程
  热点推荐
破解封路由的方法详解
技巧篇:只用这一招就能拒绝全部的…
挂马方法和技巧大汇总
网络安全防护:如何防止远程入侵
如何解决:系统开机就弹出广告网页…
彻底防御U盘病毒
安全配置交换机端口提高网络安全性…
浅析网络安全审计原理和技术(2)
用U盘就可以去除win XP管理员密码…
电脑硬盘各逻辑盘用鼠标左键双击它…
详解网站挂马的手段
新手认识;网银账号相关知识
ARP欺骗和ICMP欺骗催生全新DOS工具…
浅析网络安全审计原理和技术(1)
木马最基本的隐藏:不可见窗体和隐…
  最近更新
.NET C# 和Java开发人员岗位切换
模拟登录人人网
HttpWebRequest以及HttpWebRespon…
HttpClient使用说明
Winform为Combobox树添加数据
C#之允许DataGridView选中整行
C#中DataGridView只能选择一行禁止…
为自动填充列调整大小期间不能执行…
c# winform设置listBox如何设置te…
c#的委托(代理)和事件
C# Task 任务计划
C# socket 多线程多管道可断点传送…
让ListBox的滚动条滚动到最底部
c#用事件模式实现通知
什么是异步编程,为什么会需要异…

关于我们 | 网站建设 | 技术辅导 | 常见问题 | 联系我们 | 友情链接

夜鹰教程网 版权所有 www.yyjcw.com All rights reserved 备案号:蜀ICP备08011740号3